日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學(xué)無(wú)先后,達(dá)者為師

網(wǎng)站首頁(yè) 編程語(yǔ)言 正文

關(guān)于?React?中?useEffect?使用問(wèn)題淺談_React

作者:dxh_hxd ? 更新時(shí)間: 2022-08-19 編程語(yǔ)言

前言

最近看了一下 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 中 依賴 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 =&gt; {
  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)。現(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ì)影響用戶的交互體驗(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í)行讓我有些意外。

原文鏈接:https://juejin.cn/post/7113519924479262757

欄目分類
最近更新