模拟React.useEffect
const React = {
hookState: [],
stateIndex: 0,
useState(initialValue) {
// useState内部的模拟实现可以参考上一篇文章
...
},
useEffect(callback, nextStates) {
// 记录当前state下标
const cacheIndex = this.stateIndex;
if (this.hookState[cacheIndex]) {
// 如果存在历史值,就取值
const [preUnmountFunc, preStates] = this.hookState[cacheIndex];
if (!Array.isArray(preStates)) {
// 如果第二个参数不为数组, 则每次都执行callback(这里简单模拟,实际), 用setTimeout模拟异步调用
setTimeout(() => {
if (typeof preUnmountFunc === 'function') preUnmountFunc();
// useEffect有返回值, 是个函数, 作用相当于vue2的beforeDestroy
const unmountFunc = callback();
// 将返回值(函数)和states存起来
this.hookState[cacheIndex] = [unmountFunc, nextStates]
}, 0);
} else {
// 如果第二个参数是个数组, 则比较preStates 和 nextStates 的每一项, 都相等返回true
let bol = preStates.every((preState, index) => {
return nextStates[index] === preState;
});
if (!bol) {
// 不是都相等, 则执行callback并将结果给stack赋值, 用setTimeout模拟异步调用
setTimeout(() => {
if (typeof preUnmountFunc === 'function') preUnmountFunc();
const unmountFunc = callback();
this.hookState[cacheIndex] = [unmountFunc, nextStates]
}, 0);
}
}
} else {
// 如果不存在历史值, 执行callback并将结果给stack赋值, 用setTimeout模拟异步调用
setTimeout(() => {
const unmountFunc = callback();
this.hookState[cacheIndex] = [unmountFunc, nextStates]
}, 0);
}
// state的下标累加
this.stateIndex++;
},
};
模拟一个函数式组件
function functionComponent() {
const [num1, setNum1] = React.useState(1);
React.useEffect(() => {
console.log('dom-挂载');
setTimeout(() => {
setNum1(100)
}, 2000);
return () => {
console.log('组件卸载')
}
}, []);
React.useEffect(() => {
console.log('监听num1', num1)
return () => {
console.log('监听num1-卸载')
}
}, [num1]);
console.log('function-render');
return {
num1,
setNum1,
}
};
模拟组件调用
var instance = functionComponent();
打印如下
// function-render
// dom-挂载
// 监听num1 1
隔2s后
// function-render
// 监听num1-卸载
// 监听num1 100