關(guān)于?React?中?useEffect?使用問(wèn)題淺談
前言
最近看了一下 ant-design 中的 tree 組件源碼時(shí)發(fā)現(xiàn) useEffect 中根據(jù) props 來(lái)計(jì)算當(dāng)前函數(shù)組件的 state 的,感到好奇,因?yàn)檫@樣會(huì)導(dǎo)致應(yīng)用重新繪制一次,這樣才復(fù)雜場(chǎng)景下會(huì)對(duì)應(yīng)用有一定的性能影響。為了驗(yàn)證自己猜想是否正確做了一下實(shí)踐。這里的 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)
這里有兩個(gè)組件, APP 函數(shù)組件有一個(gè) number1 的 state,并作用 Foo 函數(shù)組件的 number props傳遞給子組件。Foo 子組件在 useEffect 中 依賴(lài) number 的變化來(lái)更新該組件的 number2 state。
為了監(jiān)聽(tīng) root 節(jié)點(diǎn)變化的情況我使用了 MutationObserver API 來(lái)看看監(jiān)聽(tīng)回調(diào)函數(shù)執(zhí)行了多少次,所以在測(cè)試代碼中增加了如下代碼
const root = document.getElementById('root');
const observer = new MutationObserver(mutations => {
console.log(mutations)
} )
observer.observe(root, {
childList: true,
subtree: true
})
來(lái)看一下第一渲染時(shí)界面輸出的效果

可以看到 MutationObserver 回調(diào)被執(zhí)行了兩次, mutations 中有兩項(xiàng)新增記錄,對(duì)應(yīng) root 的新增兩個(gè)子節(jié)點(diǎn)?,F(xiàn)在再看看我點(diǎn)【更新number1】按鈕之后的結(jié)果

可以看到 MutationObserver 這個(gè)回調(diào)被執(zhí)行了兩次,也就是但這個(gè)按鈕的時(shí)候頁(yè)面繪制了兩次。
優(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);
/**
* 這里例子可能不太好,因?yàn)榈珡倪@里例子來(lái)看 number 沒(méi)必要再調(diào)用
* useState,實(shí)際項(xiàng)目應(yīng)用場(chǎng)景中有的比較復(fù)雜的邏輯,狀態(tài)之間有關(guān)聯(lián)是
* 比較常見(jià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ù)傳給子組件就行。這樣我們?cè)賮?lái)看一下點(diǎn)擊【更新number1】之后的效果圖

可以看看到這次 MutationObserver 的回調(diào)只被執(zhí)行了一次。
總結(jié)
項(xiàng)目中還是盡量減少應(yīng)用的重復(fù)繪制次數(shù),不然會(huì)影響用戶(hù)的交互體驗(yàn),最差的情況可能還會(huì)看到每次繪制的中間狀態(tài),視覺(jué)上給人一種很卡的感覺(jué)。雖然性能提升上去了,但是代碼的可維護(hù)性變差了,這種的就看你怎么平衡了,如果性能如果能接受的話,個(gè)人還是感覺(jué)代碼的可維護(hù)性重要些。實(shí)踐的時(shí)候還發(fā)現(xiàn)了一個(gè) MutationObserver 的一個(gè)問(wèn)題,就是我對(duì) DOM 節(jié)點(diǎn)的文本進(jìn)行修改的時(shí)候,MutationObserver 的回調(diào)居然沒(méi)有執(zhí)行讓我有些意外。
到此這篇關(guān)于關(guān)于 React 中 useEffect 使用問(wèn)題淺談的文章就介紹到這了,更多相關(guān)React useEffect 使用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用useImperativeHandle時(shí)父組件第一次沒(méi)拿到子組件的問(wèn)題
這篇文章主要介紹了使用useImperativeHandle時(shí)父組件第一次沒(méi)拿到子組件的問(wèn)題及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-08-08
React-Native之TextInput組件的設(shè)置以及如何獲取輸入框的內(nèi)容
這篇文章主要介紹了React-Native之TextInput組件的設(shè)置以及如何獲取輸入框的內(nèi)容問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-05-05
React 模塊聯(lián)邦多模塊項(xiàng)目實(shí)戰(zhàn)詳解
這篇文章主要介紹了React 模塊聯(lián)邦多模塊項(xiàng)目實(shí)戰(zhàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10
基于React-Dropzone開(kāi)發(fā)上傳組件功能(實(shí)例演示)
這篇文章主要介紹了基于React-Dropzone開(kāi)發(fā)上傳組件,主要講述的是在React-Flask框架上開(kāi)發(fā)上傳組件的技巧,需要的朋友可以參考下2021-08-08
React系列useSyncExternalStore學(xué)習(xí)詳解
這篇文章主要為大家介紹了React系列useSyncExternalStore的學(xué)習(xí)及示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07

