1、useEffect使用方法
function AppPlayer(play) {
const [num, setNum] = useState(0);
let interval;
useEffect(() => {
interval = setInterval(() => {
setNum(pre=> pre + 1)
console.log('setInterval',num)
}, 1000);
return () => {
clearInterval(interval);
console.log("setInterval return");
};
}, []);
}
- useEffect两个参数,第一个参数是一个方法,方法里面包含的是执行的逻辑,方法返回的是清理上一次渲染的逻辑。
- 第二个参数,是代表执行的时机,当参数为空则每次渲染都会执行,当参数为空数组[],则只会在第一次渲染完执行一次,当参数不为空,则参数里面的值代表执行的一个依赖,只要这里面的参数有变化就会执行。
2、useEffect简单版实现
实现思路:
-
全局状态:
prevEffect和prevDeps用于存储上一次执行的 effect 清理函数和依赖项。这不同于 React 的实际实现,React 会为每个组件实例和每个 hook 调用维护独立的状态。 -
useEffect函数:1、接受一个副作用函数
effect和一个依赖项数组deps。2、判断是否没有依赖项
hasNoDeps或者依赖项是否发生变化hasChangedDeps。3、如果没有依赖项或依赖项发生了变化,首先调用上一次存储的 effect 清理函数(如果存在),然后执行当前的 effect 并存储其清理函数和依赖项。
-
组件
MyComponent:1、使用自定义的
useState和useEffect。2、
useEffect中的副作用函数会在count变化时执行,并返回一个清理函数。 -
渲染过程:
render函数模拟 React 的渲染过程,每次状态更新都会重新调用MyComponent并执行副作用。 -
模拟用户交互:
通过调用
setStateCallback模拟用户点击按钮,更新状态并触发重新渲染和副作用。
// 存储上一个 effect 和依赖项的全局变量
let prevEffect;
let prevDeps;
// 自定义 useEffect 实现
function useEffect(effect, deps) {
const hasNoDeps = !deps;
const hasChangedDeps = prevDeps
? !deps.every((dep, i) => dep === prevDeps[i])
: true;
// 如果没有依赖项或者依赖项发生了变化
if (hasNoDeps || hasChangedDeps) {
// 如果存在上一个 effect 清理函数,先执行清理函数
if (prevEffect) {
prevEffect();
}
// 执行当前 effect,并将清理函数存储在 prevEffect
prevEffect = effect();
// 存储当前的依赖项
prevDeps = deps;
}
}
// 模拟一个简单的组件
function MyComponent() {
// 模拟 useState
const [count, setCount] = useState(0);
// 使用自定义 useEffect
useEffect(() => {
console.log('Effect executed: Count is', count);
// 返回一个清理函数
return () => {
console.log('Cleanup: Count was', count);
};
}, [count]);
console.log('MyComponent Rendered with count:', count);
// 模拟用户点击按钮来增加计数
function handleClick() {
setCount(count + 1);
}
return { handleClick };
}
// 模拟全局状态存储和渲染过程
let state;
let setStateCallback;
function useState(initialValue) {
if (state === undefined) {
state = initialValue;
}
function setState(newValue) {
state = newValue;
render();
}
return [state, setState];
}
function render() {
const componentInstance = MyComponent();
setStateCallback = componentInstance.handleClick;
}
// 初始渲染
render();
// 模拟用户交互
console.log('Initial state:', state);
setStateCallback();
console.log('State after one click:', state);
setStateCallback();
console.log('State after two clicks:', state);