使用 React hooks 實(shí)現(xiàn)類所有生命周期
在 React 16.8 之前,函數(shù)組件也稱為無(wú)狀態(tài)組件,因?yàn)楹瘮?shù)組件也不能訪問(wèn) react 生命周期,也沒有自己的狀態(tài)。react 自 16.8 開始,引入了 Hooks 概念,使得函數(shù)組件中也可以擁有自己的狀態(tài),并且可以模擬對(duì)應(yīng)的生命周期。
應(yīng)該在什么時(shí)候使用 Hooks 呢?
官方并不建議把原有的 class 組件,大規(guī)模重構(gòu)成 Hooks,而是有一個(gè)漸進(jìn)過(guò)程:
- 首先,原有的函數(shù)組件如果需要自己的狀態(tài)或者需要訪問(wèn)生命周期函數(shù),那么用 Hooks 是再好不過(guò)了;
- 另外就是,可以先在一些邏輯較簡(jiǎn)單的組件上嘗試 Hooks ,在使用起來(lái)相對(duì)較熟悉,且組內(nèi)人員比較能接受的前提下,再擴(kuò)大 Hooks 的使用范圍。
那么相對(duì)于傳統(tǒng)class, Hooks 有哪些優(yōu)勢(shì)?
- State Hook 使得組件內(nèi)的狀態(tài)的設(shè)置和更新相對(duì)獨(dú)立,這樣便于對(duì)這些狀態(tài)單獨(dú)測(cè)試并復(fù)用。
- Hook 將組件中相互關(guān)聯(lián)的部分拆分成更小的函數(shù)(比如設(shè)置訂閱或請(qǐng)求數(shù)據(jù)),而并非強(qiáng)制按照生命周期劃分,這樣使得各個(gè)邏輯相對(duì)獨(dú)立和清晰。
class 生命周期在 Hooks 中的實(shí)現(xiàn)
Hooks 組件更接近于實(shí)現(xiàn)狀態(tài)同步,而不是響應(yīng)生命周期事件。但是,由于先熟悉的 class 的生命周期,在寫代碼時(shí),難免會(huì)受此影響,那么 Hooks 中如何模擬 class 的中的生命周期呢:
總結(jié):
class 組件 | Hooks 組件 |
---|---|
constructor | useState |
getDerivedStateFromProps | useEffect 手動(dòng)對(duì)比 props, 配合 useState 里面 update 函數(shù) |
shouldComponentUpdate | React.memo |
render | 函數(shù)本身 |
componentDidMount | useEffect 第二個(gè)參數(shù)為[] |
componentDidUpdate | useEffect 配合useRef |
componentWillUnmount | useEffect 里面返回的函數(shù) |
componentDidCatch | 無(wú) |
getDerivedStateFromError | 無(wú) |
代碼實(shí)現(xiàn):
import React, { useState, useEffect, useRef, memo } from 'react'; // 使用 React.memo 實(shí)現(xiàn)類似 shouldComponentUpdate 的優(yōu)化, React.memo 只對(duì) props 進(jìn)行淺比較 const UseEffectExample = memo((props) => { console.log("===== UseStateExample render======="); // 聲明一個(gè)叫 “count” 的 state 變量。 const [count, setCount] = useState(0); const [count2, setCount2] = useState(0); const [fatherCount, setFatherCount] = useState(props.fatherCount) console.log(props); // 模擬 getDerivedStateFromProps useEffect(() => { // props.fatherCount 有更新,才執(zhí)行對(duì)應(yīng)的修改,沒有更新執(zhí)行另外的邏輯 if(props.fatherCount == fatherCount ){ console.log("======= 模擬 getDerivedStateFromProps======="); console.log(props.fatherCount, fatherCount); }else{ setFatherCount(props.fatherCount); console.log(props.fatherCount, fatherCount); } }) // 模擬DidMount useEffect(() => { console.log("=======只渲染一次(相當(dāng)于DidMount)======="); console.log(count); }, []) // 模擬DidUpdate const mounted = useRef(); useEffect(() => { console.log(mounted); if (!mounted.current) { mounted.current = true; } else { console.log("======count 改變時(shí)才執(zhí)行(相當(dāng)于DidUpdate)========="); console.log(count); } }, [count]) // 模擬 Didmount和DidUpdate 、 unmount useEffect(() => { // 在 componentDidMount,以及 count 更改時(shí) componentDidUpdate 執(zhí)行的內(nèi)容 console.log("======初始化、或者 count 改變時(shí)才執(zhí)行(相當(dāng)于Didmount和DidUpdate)========="); console.log(count); return () => { console.log("====unmount======="); console.log(count); } }, [count]) return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> <button onClick={() => setCount2(count2 + 1)}> Click me2 </button> </div> ); }); export default UseEffectExample;
注意事項(xiàng)
- useState 只在初始化時(shí)執(zhí)行一次,后面不再執(zhí)行;
- useEffect 相當(dāng)于是 componentDidMount,componentDidUpdate 和 componentWillUnmount 這三個(gè)函數(shù)的組合,可以通過(guò)傳參及其他邏輯,分別模擬這三個(gè)生命周期函數(shù);
- useEffect 第二個(gè)參數(shù)是一個(gè)數(shù)組,如果數(shù)組為空時(shí),則只執(zhí)行一次(相當(dāng)于componentDidMount);如果數(shù)組中有值時(shí),則該值更新時(shí),useEffect 中的函數(shù)才會(huì)執(zhí)行;如果沒有第二個(gè)參數(shù),則每次render時(shí),useEffect 中的函數(shù)都會(huì)執(zhí)行;
- React 保證了每次運(yùn)行 effect 的同時(shí),DOM 都已經(jīng)更新完畢,也就是說(shuō) effect 中的獲取的 state 是最新的,但是需要注意的是,effect 中返回的函數(shù)(其清除函數(shù))中,獲取到的 state 是更新前的。
- 傳遞給 useEffect 的函數(shù)在每次渲染中都會(huì)有所不同,這是刻意為之的。事實(shí)上這正是可以在 effect 中獲取最新的 count 的值,而不用擔(dān)心其過(guò)期的原因。每次我們重新渲染,都會(huì)生成新的 effect,替換掉之前的。某種意義上講,effect 更像是渲染結(jié)果的一部分 —— 每個(gè) effect “屬于”一次特定的渲染。
- effect 的清除階段(返回函數(shù))在每次重新渲染時(shí)都會(huì)執(zhí)行,而不是只在卸載組件的時(shí)候執(zhí)行一次。它會(huì)在調(diào)用一個(gè)新的 effect 之前對(duì)前一個(gè) effect 進(jìn)行清理,從而避免了手動(dòng)去處理一些邏輯 。為了說(shuō)明這一點(diǎn),下面按時(shí)間列出一個(gè)可能會(huì)產(chǎn)生的訂閱和取消訂閱操作調(diào)用序列:
function FriendStatus(props) { // ... useEffect(() => { // ... ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange); return () => { ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange); }; }); // ... } // Mount with { friend: { id: 100 } } props ChatAPI.subscribeToFriendStatus(100, handleStatusChange); // 運(yùn)行第一個(gè) effect // Update with { friend: { id: 200 } } props ChatAPI.unsubscribeFromFriendStatus(100, handleStatusChange); // 清除上一個(gè) effect ChatAPI.subscribeToFriendStatus(200, handleStatusChange); // 運(yùn)行下一個(gè) effect // Update with { friend: { id: 300 } } props ChatAPI.unsubscribeFromFriendStatus(200, handleStatusChange); // 清除上一個(gè) effect ChatAPI.subscribeToFriendStatus(300, handleStatusChange); // 運(yùn)行下一個(gè) effect // Unmount ChatAPI.unsubscribeFromFriendStatus(300, handleStatusChange); // 清除最后一個(gè) effect
到此這篇關(guān)于使用 React hooks 怎么實(shí)現(xiàn)類里面的所有生命周期的文章就介紹到這了,更多相關(guān)React hooks生命周期內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解React-Router中Url參數(shù)改變頁(yè)面不刷新的解決辦法
這篇文章主要介紹了詳解React-Router中Url參數(shù)改變頁(yè)面不刷新的解決辦法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-05-05使用react-color實(shí)現(xiàn)前端取色器的方法
本文通過(guò)代碼給大家介紹了使用react-color實(shí)現(xiàn)前端取色器的方法,代碼簡(jiǎn)單易懂,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2021-11-11Remix集成antd和pro-components的過(guò)程示例
這篇文章主要為大家介紹了Remix集成antd和pro-components的過(guò)程示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03React?正確使用useCallback?useMemo的方式
這篇文章主要介紹了React?正確使用useCallback?useMemo的方式,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的朋友可以參考一下2022-08-08使用React代碼動(dòng)態(tài)生成柵格布局的方法
這篇文章主要介紹了使用React簡(jiǎn)短代碼動(dòng)態(tài)生成柵格布局的方法,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-05-05