網站首頁 編程語言 正文
在 React 16.8 之前,函數組件也稱為無狀態組件,因為函數組件也不能訪問 react 生命周期,也沒有自己的狀態。react 自 16.8 開始,引入了 Hooks 概念,使得函數組件中也可以擁有自己的狀態,并且可以模擬對應的生命周期。
應該在什么時候使用 Hooks 呢?
官方并不建議把原有的 class 組件,大規模重構成 Hooks,而是有一個漸進過程:
- 首先,原有的函數組件如果需要自己的狀態或者需要訪問生命周期函數,那么用 Hooks 是再好不過了;
- 另外就是,可以先在一些邏輯較簡單的組件上嘗試 Hooks ,在使用起來相對較熟悉,且組內人員比較能接受的前提下,再擴大 Hooks 的使用范圍。
那么相對于傳統class, Hooks 有哪些優勢?
- State Hook 使得組件內的狀態的設置和更新相對獨立,這樣便于對這些狀態單獨測試并復用。
- Hook 將組件中相互關聯的部分拆分成更小的函數(比如設置訂閱或請求數據),而并非強制按照生命周期劃分,這樣使得各個邏輯相對獨立和清晰。
class 生命周期在 Hooks 中的實現
Hooks 組件更接近于實現狀態同步,而不是響應生命周期事件。但是,由于先熟悉的 class 的生命周期,在寫代碼時,難免會受此影響,那么 Hooks 中如何模擬 class 的中的生命周期呢:
總結:
class 組件 | Hooks 組件 |
---|---|
constructor | useState |
getDerivedStateFromProps | useEffect 手動對比 props, 配合 useState 里面 update 函數 |
shouldComponentUpdate | React.memo |
render | 函數本身 |
componentDidMount | useEffect 第二個參數為[] |
componentDidUpdate | useEffect 配合useRef |
componentWillUnmount | useEffect 里面返回的函數 |
componentDidCatch | 無 |
getDerivedStateFromError | 無 |
代碼實現:
import React, { useState, useEffect, useRef, memo } from 'react';
// 使用 React.memo 實現類似 shouldComponentUpdate 的優化, React.memo 只對 props 進行淺比較
const UseEffectExample = memo((props) => {
console.log("===== UseStateExample render=======");
// 聲明一個叫 “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 有更新,才執行對應的修改,沒有更新執行另外的邏輯
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("=======只渲染一次(相當于DidMount)=======");
console.log(count);
}, [])
// 模擬DidUpdate
const mounted = useRef();
useEffect(() => {
console.log(mounted);
if (!mounted.current) {
mounted.current = true;
} else {
console.log("======count 改變時才執行(相當于DidUpdate)=========");
console.log(count);
}
}, [count])
// 模擬 Didmount和DidUpdate 、 unmount
useEffect(() => {
// 在 componentDidMount,以及 count 更改時 componentDidUpdate 執行的內容
console.log("======初始化、或者 count 改變時才執行(相當于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;
注意事項
- useState 只在初始化時執行一次,后面不再執行;
- useEffect 相當于是 componentDidMount,componentDidUpdate 和 componentWillUnmount 這三個函數的組合,可以通過傳參及其他邏輯,分別模擬這三個生命周期函數;
- useEffect 第二個參數是一個數組,如果數組為空時,則只執行一次(相當于componentDidMount);如果數組中有值時,則該值更新時,useEffect 中的函數才會執行;如果沒有第二個參數,則每次render時,useEffect 中的函數都會執行;
- React 保證了每次運行 effect 的同時,DOM 都已經更新完畢,也就是說 effect 中的獲取的 state 是最新的,但是需要注意的是,effect 中返回的函數(其清除函數)中,獲取到的 state 是更新前的。
- 傳遞給 useEffect 的函數在每次渲染中都會有所不同,這是刻意為之的。事實上這正是可以在 effect 中獲取最新的 count 的值,而不用擔心其過期的原因。每次我們重新渲染,都會生成新的 effect,替換掉之前的。某種意義上講,effect 更像是渲染結果的一部分 —— 每個 effect “屬于”一次特定的渲染。
- effect 的清除階段(返回函數)在每次重新渲染時都會執行,而不是只在卸載組件的時候執行一次。它會在調用一個新的 effect 之前對前一個 effect 進行清理,從而避免了手動去處理一些邏輯 。為了說明這一點,下面按時間列出一個可能會產生的訂閱和取消訂閱操作調用序列:
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); // 運行第一個 effect
// Update with { friend: { id: 200 } } props
ChatAPI.unsubscribeFromFriendStatus(100, handleStatusChange); // 清除上一個 effect
ChatAPI.subscribeToFriendStatus(200, handleStatusChange); // 運行下一個 effect
// Update with { friend: { id: 300 } } props
ChatAPI.unsubscribeFromFriendStatus(200, handleStatusChange); // 清除上一個 effect
ChatAPI.subscribeToFriendStatus(300, handleStatusChange); // 運行下一個 effect
// Unmount
ChatAPI.unsubscribeFromFriendStatus(300, handleStatusChange); // 清除最后一個 effect
原文鏈接:https://blog.csdn.net/zz130428/article/details/128921417
相關推薦
- 2023-10-10 函數柯里化的簡單實現和應用
- 2022-07-26 3dmax2021 中的各種顯示相關如何設置?
- 2022-07-18 async+await:發送Ajax請求
- 2024-03-07 SpringAOP基于XML方式實現(了解)
- 2022-11-10 Python+Selenium實現瀏覽器的控制操作_python
- 2022-03-14 golang實現子網掩碼和網絡位長度相互轉換
- 2022-03-23 CentOS7防火墻和端口相關命令介紹_Linux
- 2023-01-31 golang定時任務cron項目實操指南_Golang
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支