在React网站的这段代码中:
import { useState, useEffect } from 'react';
export default function App() {
const [position, setPosition] = useState({ x: 0, y: 0 });
const [canMove, setCanMove] = useState(true);
useEffect(() => {
function handleMove(e) {
setPosition({ x: e.clientX, y: e.clientY });
}
if (canMove) {
window.addEventListener('pointermove', handleMove);
return () => window.removeEventListener('pointermove', handleMove);
}
}, [canMove]);
return (
<>
<label>
<input type="checkbox"
checked={canMove}
onChange={e => setCanMove(e.target.checked)}
/>
The dot is allowed to move
</label>
<hr />
<div style={{
position: 'absolute',
backgroundColor: 'pink',
borderRadius: '50%',
opacity: 0.6,
transform: `translate(${position.x}px, ${position.y}px)`,
pointerEvents: 'none',
left: -20,
top: -20,
width: 40,
height: 40,
}} />
</>
);
}
useEffect 依赖于变量 canMove。因此,当 canMove 为 true 且效果仅运行一次且对于浏览器中的每个指针移动时,都会触发添加的事件侦听器。当 canMove 为 false 时,React 应该在设置之前先运行清理。
但是 return 语句是在 canMove 的条件下的,现在它是 false,所以控件不应该进入那里。那么,当 Effect 设置运行时,React 会记录清理函数吗?如果这样做,React 会存储清理函数,直到触发下一个 useEffect。
但是 return 语句是在 canMove 的条件下的,现在它是 false,所以控件不应该进入那里。那么,当 Effect 设置运行时,React 会记录清理函数吗?
是的,react 保留对前一个效果的清理函数的引用并调用它。
如果这样做,React 会存储清理函数,直到触发下一个 useEffect。
useEffect 的实现(在第一个之后的渲染上)称为 updateEffectImpl,在此处找到。它调用函数
pushEffect
,然后将结果值保存到 hook.memoizedState
。 pushEffect
创建并返回一个包含“create”函数的对象。 create
是您传递给使用效果的函数,它可能会也可能不会返回清理函数。
hook.memoizedState = pushEffect(
HookHasEffect | hookFlags,
create,
inst,
nextDeps,
);
稍后,在 ReactFiberCommitWork.js 中,调用
create
函数并保存销毁函数(如果有)。
const create = effect.create;
const inst = effect.inst;
destroy = create();
inst.destroy = destroy;