關(guān)于?React?中?useEffect?使用問題淺談
前言
最近看了一下 ant-design 中的 tree 組件源碼時發(fā)現(xiàn) useEffect 中根據(jù) props 來計算當(dāng)前函數(shù)組件的 state 的,感到好奇,因為這樣會導(dǎo)致應(yīng)用重新繪制一次,這樣才復(fù)雜場景下會對應(yīng)用有一定的性能影響。為了驗證自己猜想是否正確做了一下實踐。這里的 React 是官方 16.12.0
的源碼。
優(yōu)化前
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 函數(shù)組件有一個 number1 的 state,并作用 Foo 函數(shù)組件的 number props傳遞給子組件。Foo 子組件在 useEffect 中 依賴 number 的變化來更新該組件的 number2 state。
為了監(jiān)聽 root 節(jié)點變化的情況我使用了 MutationObserver API 來看看監(jiān)聽回調(diào)函數(shù)執(zhí)行了多少次,所以在測試代碼中增加了如下代碼
const root = document.getElementById('root'); const observer = new MutationObserver(mutations => { console.log(mutations) } ) observer.observe(root, { childList: true, subtree: true })
來看一下第一渲染時界面輸出的效果
可以看到 MutationObserver 回調(diào)被執(zhí)行了兩次, mutations 中有兩項新增記錄,對應(yīng) root 的新增兩個子節(jié)點?,F(xiàn)在再看看我點【更新number1】按鈕之后的結(jié)果
可以看到 MutationObserver 這個回調(diào)被執(zhí)行了兩次,也就是但這個按鈕的時候頁面繪制了兩次。
優(yōu)化后
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 沒必要再調(diào)用 * useState,實際項目應(yīng)用場景中有的比較復(fù)雜的邏輯,狀態(tài)之間有關(guān)聯(lián)是 * 比較常見的 */ 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)
優(yōu)化有的代碼就是把 Foo 狀態(tài)提升到父組件中,然后把狀態(tài)以及更新函數(shù)傳給子組件就行。這樣我們再來看一下點擊【更新number1】之后的效果圖
可以看看到這次 MutationObserver 的回調(diào)只被執(zhí)行了一次。
總結(jié)
項目中還是盡量減少應(yīng)用的重復(fù)繪制次數(shù),不然會影響用戶的交互體驗,最差的情況可能還會看到每次繪制的中間狀態(tài),視覺上給人一種很卡的感覺。雖然性能提升上去了,但是代碼的可維護(hù)性變差了,這種的就看你怎么平衡了,如果性能如果能接受的話,個人還是感覺代碼的可維護(hù)性重要些。實踐的時候還發(fā)現(xiàn)了一個 MutationObserver 的一個問題,就是我對 DOM 節(jié)點的文本進(jìn)行修改的時候,MutationObserver 的回調(diào)居然沒有執(zhí)行讓我有些意外。
到此這篇關(guān)于關(guān)于 React 中 useEffect 使用問題淺談的文章就介紹到這了,更多相關(guān)React useEffect 使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
React-Hooks之useImperativeHandler使用介紹
這篇文章主要為大家介紹了React-Hooks之useImperativeHandler使用介紹,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07React使用highlight.js Clipboard.js實現(xiàn)代碼高亮復(fù)制
這篇文章主要為大家介紹了React使用highlight.js Clipboard.js實現(xiàn)代碼高亮復(fù)制功能示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04詳解React項目的服務(wù)端渲染改造(koa2+webpack3.11)
本篇文章主要介紹了詳解React項目的服務(wù)端渲染改造(koa2+webpack3.11),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-03-03React useMemo與useCallabck有什么區(qū)別
useCallback和useMemo是一樣的東西,只是入?yún)⒂兴煌?,useCallback緩存的是回調(diào)函數(shù),如果依賴項沒有更新,就會使用緩存的回調(diào)函數(shù);useMemo緩存的是回調(diào)函數(shù)的return,如果依賴項沒有更新,就會使用緩存的return2022-12-12React腳手架config-overrides.js文件的配置方式
這篇文章主要介紹了React腳手架config-overrides.js文件的配置方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-10-10