首先 我们先模拟一个useState
function useState(initVal) {
let _val = initVal;
const state = _val;
function setState(newVal) {
_val = newVal;
}
return [state, setState];
}
const [count, setCount] = useState(0);
console.log(count);
setCount(2);
console.log(count);
但是log 出来的count并不是我们所期望的 0 2,而是 0 0; 为什么呢? 因为在[count, setCount] = useState(0)count 复制的是 initVal, 修改 _val 的值, 而 count 仍然是initVal的值
如何让他恢复正常呢,我们可以使用方法来获取state
function useState(initVal) {
let _val = initVal;
const state = () => _val;
function setState(newVal) {
_val = newVal;
}
return [state, setState];
}
const [count, setCount] = useState(0);
console.log(count());
setCount(2);
console.log(count());
但是如果我们想真正模拟Hooks,就不能这样做。
我们可以用如下代码模拟 React, 主要使用闭包和数组模拟Hook,使用 hook[index] 存放 state 或者 依赖
// module pattern
const React = (function() {
let hooks = []; // 存放所以使用的 hook
let idx = 0; // hook 指针,来保证 hook 顺序的正常调用
function useState(initVal) {
const state = hooks[idx] || initVal;
const _idx = idx; // _idx 确保 setState 修改的是同一个state
function setState(newVal) {
hooks[_idx] = newVal;
}
idx++; // 如果再使用 useState, 指向 hook 数组的下一个
return [state, setState];
}
function useEffect(callback, deps) {
const oldDeps = hooks[idx];
let hasChange = true;
if (oldDeps) {
hasChange = deps.some((dep, i) => !Object.is(dep, oldDeps[i]));
}
if (hasChange) callback();
hooks[idx] = deps;
idx++; // 如果再使用 useEffect, 指向 hook 数组的下一个
}
function render(Component) {
const C = Component();
C.render();
idx = 0; // 每次 render 重置,确保 hooks 指针顺序
return C;
}
return {
Component,
render,
useState,
useEffect
};
})();
const { useState, useEffect, render } = React;
function Component() {
const [count, setCount] = useState(0);
const [type, setType] = useState("");
useEffect(() => {
console.log("jack");
}, [count]);
return {
render: () => {
document.body.innerHTML = "";
const div = document.createElement("div");
div.innerText = count;
document.body.appendChild(div);
},
click: () => setCount(count + 1),
type: () => setType("apple"),
say: () => console.log(count, type)
};
}
let App = render(Component);
setInterval(() => {
App.click();
App = render(Component); // 模拟 rerender
}, 1000);
效果看下面连接
mock react hooks
首先 我们先模拟一个useState
但是log 出来的count并不是我们所期望的 0 2,而是 0 0; 为什么呢? 因为在[count, setCount] = useState(0)count 复制的是 initVal, 修改 _val 的值, 而 count 仍然是initVal的值
如何让他恢复正常呢,我们可以使用方法来获取state
但是如果我们想真正模拟Hooks,就不能这样做。
我们可以用如下代码模拟 React, 主要使用闭包和数组模拟Hook,使用 hook[index] 存放 state 或者 依赖
效果看下面连接
mock react hooks