在 深入了解react hooks原理Ⅰ 实现了useState
,遗留了两个问题
- 使用多个 useState 是否能够符合预期
- useEffect 是怎么实现的
使用 useState 是否能够符合预期
我们新增一个状态
function Component() {
const [count, setCount] = React.useState(1);
const [text, setText] = React.useState("hello");
return {
render: () =>
console.log({
count,
text
}),
click: () => setCount(count + 1),
say: (text) => setText(text)
};
}
可以看到,每次render的结果跟我们预期的不一致,每次 count
和 text
都是最后赋值的结果,这时候可以通过数组来存储 useState
,我们改写下React模块,新增一个 hooks
数组来存储state的值
const React = (function () {
let hooks = []; // 定义一个hooks数组存储值
let idx = 0;
function useState(initVal) {
const state = hooks[idx] || initVal;
const _idx = idx; // 保留首次useState下标,通过下标可以记录当前state的位置
const setState = (newVal) => {
hooks[_idx] = newVal;
};
idx++;
return [state, setState];
}
function render(Component) {
const C = new Component();
C.render();
idx = 0; // 每次render完成后,下标置0
return C;
}
return {
useState,
render
};
})();
function Component() {
const [count, setCount] = React.useState(1);
const [text, setText] = React.useState("hello");
return {
render: () =>
console.log({
count,
text
}),
click: () => setCount(count + 1),
say: (text) => setText(text)
};
}
这样结果就一致了
useEffect实现
我们先来看看 useEffect
的语法
useEffect(callback, deps);
第一个参数是回调 callback
,第二个参数是依赖的数组 deps
回到上面的 useState
实现,我们通过新增 hooks
数组存储 useState
的值,也可以继续通过 hooks
数组来存储依赖的值,也是我们可以实现一个 useEffect
function useEffect(cb, deps) {
// 旧的依赖值,这里的依赖是存放在hooks的所有state后面
const oldDeps = hooks[idx];
let hasChanged = true;
if (oldDeps) {
// 通过 Object.is 来判断依赖是否改变
hasChanged = deps.some((val, i) => !Object.is(val, oldDeps[i]));
}
if (hasChanged) cb();
hooks[idx] = deps;
idx++;
}