網站首頁 編程語言 正文
引言
在介紹一下這兩個hooks的作用之前,我們先來回顧一下react中的性能優化。在hooks誕生之前,如果組件包含內部state,我們都是基于class的形式來創建組件。當時我們也知道,react中,性能的優化點在于:
調用setState,就會觸發組件的重新渲染,無論前后的state是否不同 父組件更新,子組件也會自動的更新 基于上面的兩點,我們通常的解決方案是:使用immutable進行比較,在不相等的時候調用setState;在shouldComponentUpdate中判斷前后的props和state,如果沒有變化,則返回false來阻止更新。
在hooks出來之后,我們能夠使用function的形式來創建包含內部state的組件。但是,使用function的形式,失去了上面的shouldComponentUpdate,我們無法通過判斷前后狀態來決定是否更新。而且,在函數組件中,react不再區分mount和update兩個狀態,這意味著函數組件的每一次調用都會執行其內部的所有邏輯,那么會帶來較大的性能損耗。因此useMemo 和useCallback就是解決性能問題的殺手锏。
對比
useCallback和useMemo的參數跟useEffect一致,他們之間最大的區別有是useEffect會用于處理副作用,而前兩個hooks不能。
useMemo和useCallback都會在組件第一次渲染的時候執行,之后會在其依賴的變量發生改變時再次執行;并且這兩個hooks都返回緩存的值,useMemo返回緩存的變量,useCallback返回緩存的函數。
useMemo
我們來看一個反例:
這里創建了兩個state,然后通過expensive函數,執行一次昂貴的計算,拿到count對應的某個值。我們可以看到:無論是修改count還是val,由于組件的重新渲染,都會觸發expensive的執行(能夠在控制臺看到,即使修改val,也會打印);
但是這里的昂貴計算只依賴于count的值,在val修改的時候,是沒有必要再次計算的。在這種情況下,我們就可以使用useMemo,只在count的值修改時,執行expensive計算:
上面我們可以看到,使用useMemo來執行昂貴的計算,然后將計算值返回,并且將count作為依賴值傳遞進去。這樣,就只會在count改變的時候觸發expensive執行,在修改val的時候,返回上一次緩存的值。
useCallback
useCallback 講完了useMemo,接下來是useCallback。useCallback跟useMemo比較類似,但它返回的是緩存的函數。我們看一下最簡單的用法:
const fnA = useCallback(fnB, [a]) 上面的useCallback會將我們傳遞給它的函數fnB返回,并且將這個結果緩存;當依賴a變更時,會返回新的函數。既然返回的是函數,我們無法很好的判斷返回的函數是否變更,所以我們可以借助ES6新增的數據類型Set來判斷,具體如下:
我們可以看到,每次修改count,set.size就會+1,這說明useCallback依賴變量count,count變更時會返回新的函數;而val變更時,set.size不會變,說明返回的是緩存的舊版本函數。
知道useCallback有什么樣的特點,那有什么作用呢?
使用場景是:有一個父組件,其中包含子組件,子組件接收一個函數作為props;通常而言,如果父組件更新了,子組件也會執行更新;但是大多數場景下,更新是沒有必要的,我們可以借助useCallback來返回函數,然后把這個函數作為props傳遞給子組件;這樣,子組件就能避免不必要的更新。
不僅是上面的例子,所有依賴本地狀態或props來創建函數,需要使用到緩存函數的地方,都是useCallback的應用場景。
多談一點 useEffect、useMemo、useCallback都是自帶閉包的。也就是說,每一次組件的渲染,其都會捕獲當前組件函數上下文中的狀態(state, props),所以每一次這三種hooks的執行,反映的也都是當前的狀態,你無法使用它們來捕獲上一次的狀態。對于這種情況,我們應該使用ref來訪問。
原文鏈接:https://juejin.cn/post/7130160515371925512
相關推薦
- 2022-05-25 kotlin將網絡上可以訪問的url圖片轉換成Base64字符串
- 2022-08-30 ORACLE分區表轉換在線重定義DBMS_REDEFINITION_oracle
- 2022-07-17 gethostbyaddr在Python3中引發UnicodeDecodeError_python
- 2022-11-19 ubuntu desktop 開啟root賬戶
- 2022-04-15 python實現選取或刪除指定列包含指定內容的行_python
- 2023-01-04 Opencv實現鼠標事件與窗口互動功能過程_python
- 2022-10-07 C#如何實現調取釘釘考勤接口的功能_C#教程
- 2022-11-15 Python中class內置方法__init__與__new__作用與區別解析_python
- 最近更新
-
- 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同步修改后的遠程分支