昨天在介绍 useEffect 的时候有提到 useEffect 中的执行顺序,今天就再做进一步的观察,来加深对於 useEffect 在 Component mount、 update 与 unmount 三个状况下的执行时机吧!
建立 App 与 Child 元件,并在 App 元件中设立 showChild 的 state 来控制要不要显示 Child 元件。并且在两个元件中都设置三个 useEffect 分别是没有 dependency array、空阵列与放置一个 state 的 dependency array。
const Child = () => {
console.log('%c Child: render start', 'color: MediumSpringGreen')
const [count, setCount] = useState(()=> {
console.log('%c Child: useState(() => 0)', 'color: tomato')
return 0
})
useEffect(() => {
console.log('%c Child: useEffect(() => {})', 'color: LightCoral')
return () => {
console.log(
'%c Child: useEffect(() => {}) cleanup',
'color: LightCoral',
)
}
})
useEffect(() => {
console.log(
'%c Child: useEffect(() => {}, [])',
'color: MediumTurquoise',
)
return () => {
console.log(
'%c Child: useEffect(() => {}, []) cleanup',
'color: MediumTurquoise',
)
}
}, [])
useEffect(() => {
console.log('%c Child: useEffect(() => {}, [count])', 'color: HotPink')
return () => {
console.log(
'%c Child: useEffect(() => {}, [count]) cleanup',
'color: HotPink',
)
}
}, [count])
const increaseHandler = () => {
setCount(prev => prev + 1)
}
console.log('%c Child: render end', 'color: MediumSpringGreen')
return (
<button className="plus" onClick={increaseHandler}>{count}</button>
)
};
function App() {
console.log('%cApp: render start', 'color: red')
const [showChild, setShowChild] = useState(()=>{
console.log('%cLazy initialize', 'color: MediumSpringGreen')
return false
})
function onChangeHandler(){
setShowChild(prev => !prev)
}
useEffect(() => {
console.log('%cApp: useEffect(() => {})', 'color: LightCoral')
return () => {
console.log('%cApp: useEffect(() => {}) cleanup', 'color: LightCoral')
}
})
useEffect(() => {
console.log('%cApp: useEffect(() => {}, [])', 'color: MediumTurquoise')
return () => {
console.log(
'%cApp: useEffect(() => {}, []) cleanup',
'color: MediumTurquoise',
)
}
}, [])
useEffect(() => {
console.log('%cApp: useEffect(() => {}, [showChild])', 'color: HotPink')
return () => {
console.log(
'%cApp: useEffect(() => {}, [showChild]) cleanup',
'color: HotPink',
)
}
}, [showChild])
console.log('%cApp: render end', 'color: red')
return (
<div className="App">
<input type='checkbox' value={showChild} onChange={onChangeHandler} />
<div>
{ showChild ? <Child /> : null}
</div>
</div>
);
}
画面与功能会如下
接下来我们来观察一下console.log 会在浏览器的 console 印出什麽吧!
从印出的结果可以发现 useState 中的 Lazy initialize 会在元件开始呼叫之後马上执行,而 useEffect 会在 render 之後开始依照顺序执行。
按下 input 会更新 App 中的 showChild state ,并 re-render,那 Lazy initialize 就不会再触发了。之後开始呼叫 Child 元件,一样会先执行 useState 的 Lazy initialize 。
接下来值得注意的是,因为 App 元件是 update 的 re-render 所以会触发之前注册的 useEffect cleanup function。然後执行完之後会先从子层的 useEffect 开始执行,再执行父层的 useEffect。
更新 Child 元件的 count state 只会影响 Child 元件,并不会影响到 父层,所以 Child 触发 re-render 然後先执行 useEffect cleanup function 再执行 useEffect 。
再次按下 input 之後,State 更新触发 App re-render ,然後因为 Child 元件 unmount 所以会触发 Child 的 useEffect cleanup function,然後再执行 App 的 useEffect cleanup function ,接者执行 useEffect 。
最後我们可以针对 Mount、Update 与 Unmount 做个小小的整理:
最後的最後关於比较完整的 hooks flow 的图表可以看 Donavon 的 Github hook-flow
该文章同步发布於:我的部落格
<<: Swift 新手-ios 应用软件开发资料与云端储存篇(二)
>>: 【Day13】Latch 的生成条件以及如何避免(下)
-战略层次 通常,CEO 负责制定公司战略或大战略,董事会的意见和高级管理团队的支持。 CISO ...
今天再来试玩一个 Try Hack Me 上面的简单题目,攻打一个 CMS (Content Man...
之後会以create-react-app建立的专案,来进行React後续的学习, 来看看建立後专案的...
本篇文章同步发表在 HKT 线上教室 部落格,线上影音教学课程已上架至 Udemy 和 Youtu...
这是 Roblox 从零开始系列,效果章节的第八个单元,今天将说明如何透过粒子来实作爆炸效果 Par...