React父子组件useEffect执行顺序不符预期的原因咨询
React useEffect执行顺序差异原因解析
问题描述
在父组件输入框中输入内容触发组件更新时,我预期的useEffect执行顺序为:
end child(子组件清理函数)child(子组件effect函数)end parent(父组件清理函数)parent(父组件effect函数)
但实际执行结果却是:
end child(子组件清理函数)end parent(父组件清理函数)child(子组件effect函数)parent(父组件effect函数)
请问产生这种差异的原因是什么?
复现代码
function App() { return ( <div className="App"> <Container/> <Parent/> </div> ); } function Parent(){ const [first, setFirst] = useState(''); const [second, setSecond] = useState(''); function final(e){ setSecond(e.target.value); } function func(e){ setFirst(e.target.value); } useEffect(()=>{ console.log('parent'); // 预期第4步,实际第4步 return ()=>{console.log('end parent')} // 预期第3步,实际第2步 },[first, second]) return ( <> <h1>I am parent</h1> <input style={{border:"1px solid black"}} value={first} onChange={(e)=>{func(e)}}/> <input style={{border:"1px solid black"}} value={second} onChange={(e)=>{final(e)}}/> { first.length < 7 ? <TestEffect fistArgument={first} secondArgument={second}/> : <h1>lorem ipsum dolor</h1> } </> ) } function TestEffect({fistArgument, secondArgument}){ const [extra, setExtra] = useState(0); const [force, setForce] = useState(0); useEffect(()=>{ console.log('child'); // 预期第2步,实际第3步 return ()=>{console.log('end child')} // 预期第1步,实际第1步 },[extra, force, fistArgument, secondArgument]) return ( <> <h1 onClick={()=>{setExtra(extra+1)}}>{fistArgument}</h1> <h1 onClick={()=>{setForce(force+1)}}>{secondArgument}</h1> </> ) } export default App;
原因分析
这种差异完全由React的副作用执行机制决定,核心点在于一次更新周期内,React会先批量执行所有需要触发的清理函数,再批量执行所有新的effect函数:
清理函数的执行逻辑:当组件的依赖项变化(或组件即将卸载)时,React会先按子组件→父组件的顺序执行所有待触发的清理函数。在你的场景中,父组件的
first状态变化后,子组件的props和父组件的effect依赖项都发生了改变,两者的旧effect都需要清理,因此会先执行子组件的end child,再执行父组件的end parent。effect函数的执行逻辑:所有清理操作完成后,React会按子组件→父组件的顺序执行新的effect函数,也就是先执行子组件的
child,再执行父组件的parent。
你的预期错误在于,误以为子组件的清理和新effect会成对执行(清理完子组件立刻执行其新effect),再处理父组件的相关逻辑,但React的批量处理机制是为了性能优化,确保同一更新周期内的副作用操作集中完成,避免零散执行带来的性能损耗和逻辑混乱。
内容的提问来源于stack exchange,提问作者hossein olfat
相关产品推荐
相关产品推荐

