網站首頁 編程語言 正文
前言
最近看了一下 ant-design 中的 tree 組件源碼時發現 useEffect 中根據 props 來計算當前函數組件的 state 的,感到好奇,因為這樣會導致應用重新繪制一次,這樣才復雜場景下會對應用有一定的性能影響。為了驗證自己猜想是否正確做了一下實踐。這里的 React 是官方 16.12.0
的源碼。
優化前
import * as React from './react-source/packages/react' import * as ReactDOM from './react-source/packages/react-dom' const root = document.getElementById('root'); function Foo({number}) { const [number2, setNumber2] = React.useState(0); React.useEffect(() => { setNumber2( number + 1) }, [number]) return <div> {number2 % 2 === 0 && <div>{number2}</div>} <button onClick={() => setNumber2(number2 + 1)}>更新 number2</button> </div> } function App() { const [number1,setNumber1] = React.useState(1); return <> {number1 % 2 === 0 && <div>{number1}</div>} <Foo number={number1}/> <button onClick={() => setNumber1(number1 + 1)}>更新 number1</button> </> } ReactDOM.render(<App/>, root)
這里有兩個組件, APP 函數組件有一個 number1 的 state,并作用 Foo 函數組件的 number props傳遞給子組件。Foo 子組件在 useEffect 中 依賴 number 的變化來更新該組件的 number2 state。
為了監聽 root 節點變化的情況我使用了 MutationObserver API 來看看監聽回調函數執行了多少次,所以在測試代碼中增加了如下代碼
const root = document.getElementById('root'); const observer = new MutationObserver(mutations => { console.log(mutations) } ) observer.observe(root, { childList: true, subtree: true })
來看一下第一渲染時界面輸出的效果
可以看到 MutationObserver 回調被執行了兩次, mutations 中有兩項新增記錄,對應 root 的新增兩個子節點。現在再看看我點【更新number1】按鈕之后的結果
可以看到 MutationObserver 這個回調被執行了兩次,也就是但這個按鈕的時候頁面繪制了兩次。
優化后
import * as React from './react-source/packages/react' import * as ReactDOM from './react-source/packages/react-dom' const root = document.getElementById('root'); const observer = new MutationObserver(mutations => { console.log(mutations) } ) observer.observe(root, { childList: true, subtree: true }) function Foo({number2,setNumber2}) { return <div> {number2 % 2 === 0 && <div>{number2}</div>} <button onClick={() => setNumber2(number2 + 1)}>更新 number2</button> </div> } function App() { const [number1,setNumber1] = React.useState(1); /** * 這里例子可能不太好,因為但從這里例子來看 number 沒必要再調用 * useState,實際項目應用場景中有的比較復雜的邏輯,狀態之間有關聯是 * 比較常見的 */ const [number2, setNumber2] = React.useState(0); return <> {number1 % 2 === 0 && <div>{number1}</div>} <Foo number2={number2} setNumber2={setNumber2}/> <button onClick={() => { let newNumber1 = number1 + 1 setNumber1(newNumber1) setNumber2(newNumber1 + 1) }}>更新 number1</button> </> } ReactDOM.render(<App/>, root)
優化有的代碼就是把 Foo 狀態提升到父組件中,然后把狀態以及更新函數傳給子組件就行。這樣我們再來看一下點擊【更新number1】之后的效果圖
可以看看到這次 MutationObserver 的回調只被執行了一次。
總結
項目中還是盡量減少應用的重復繪制次數,不然會影響用戶的交互體驗,最差的情況可能還會看到每次繪制的中間狀態,視覺上給人一種很卡的感覺。雖然性能提升上去了,但是代碼的可維護性變差了,這種的就看你怎么平衡了,如果性能如果能接受的話,個人還是感覺代碼的可維護性重要些。實踐的時候還發現了一個 MutationObserver 的一個問題,就是我對 DOM 節點的文本進行修改的時候,MutationObserver 的回調居然沒有執行讓我有些意外。
原文鏈接:https://juejin.cn/post/7113519924479262757
相關推薦
- 2022-02-11 Android之Compose頁面切換動畫介紹_Android
- 2022-02-04 防止點擊量頁面刷新增加的簡單處理方法
- 2022-04-18 WPF框架Prism中對話框Dialog用法介紹_自學過程
- 2022-06-30 Go實現分布式唯一ID的生成之雪花算法_Golang
- 2022-07-19 Swagger導出html或者PDF
- 2023-08-28 React安裝ant design組件庫,并使用
- 2023-03-03 C語言malloc與calloc區別詳解_C 語言
- 2023-04-06 Python求字符串的長度示例代碼_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同步修改后的遠程分支