<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          React Hooks 性能優(yōu)化,帶你玩轉(zhuǎn) Hooks

          共 6804字,需瀏覽 14分鐘

           ·

          2021-07-05 04:32

          點(diǎn)擊下方“前端開(kāi)發(fā)愛(ài)好者”,選擇“設(shè)為星標(biāo)
          第一時(shí)間關(guān)注技術(shù)干貨!

          前言

             React Hooks 出來(lái)很長(zhǎng)一段時(shí)間了,相信有不少朋友已經(jīng)深度使用了。無(wú)論是react本身還是其生態(tài)中,都在摸索著進(jìn)步。鑒于我使用react的經(jīng)驗(yàn),給大家分享一下 React Hooks性能優(yōu)化可以從哪幾個(gè)方面入手。至于React Hooks 的使用方式,本文就不做過(guò)多的講解了,可以自行查看https://react.docschina.org/docs/hooks-intro.html


          問(wèn)題關(guān)鍵

              要想解決性能問(wèn)題,關(guān)鍵在于組件重復(fù)渲染的處理。在使用 React Hooks 后,很多人會(huì)抱怨渲染次數(shù)變多,比如我們會(huì)把不同的數(shù)據(jù)分成多個(gè) state 變量,每個(gè)值的變化都會(huì)觸發(fā)一次渲染。

              舉個(gè)例子: 現(xiàn)在有個(gè)父子組件,子組件依賴父組件傳入的name屬性,但是父組件name屬性和text屬性變化都會(huì)導(dǎo)致Parent函數(shù)重新執(zhí)行,所以即使傳入子組件props沒(méi)有任何變化,甚至子組件沒(méi)有依賴于任何props屬性,都會(huì)導(dǎo)致子組件重新渲染

          const Child = ((props: any) => {  console.log("我是前端開(kāi)發(fā)愛(ài)好者的子組件,我更新了...");  return (      <div>          <h3>子組件</h3>          <div>text:{props.name}</div>          <div>{new Date().getTime()}</div>      </div>  )})const Parent = () => {  const [count, setCount] = useState(0);  const [text, setText] = useState("")  const handleClick = () => {      setCount(count + 1);  }  const handleInputChange = (e) => {      setText(e.target.value)  }  return (<div>      <input onChange={handleInputChange} />      <button onClick={handleClick}>+1</button>       <div>count:{count}</div>      <Child name ={text}/>  </div>)}

              上面的代碼執(zhí)行你會(huì)發(fā)現(xiàn),不管是觸發(fā) handleInputChange 還是觸發(fā) handleClick ,子組件都會(huì)在控制臺(tái)輸出   我是前端開(kāi)發(fā)愛(ài)好者的子組件,我更新了...   所以即使傳入子組件props沒(méi)有任何變化,甚至子組件沒(méi)有依賴于任何props屬性,子組件都會(huì)重新渲染。

              想要解決重復(fù)渲染的問(wèn)題,可以使用 react的親手制造升級(jí)的兒子,他有三個(gè)方法用來(lái)做優(yōu)化,分別是  React.memo       useCallback       useMemo


          • React.memo : 和 class 組件時(shí)期的 PureComponent 一樣,做簡(jiǎn)單額數(shù)據(jù)類型比較

          • useMemo : 可以用來(lái)比較復(fù)雜類型的數(shù)據(jù),不如 Object Array 等

          • useCallback : 升級(jí)版本,用于控制傳遞函數(shù)時(shí)候控制組件是否需要更新

          React.memo 

              使用memo包裹子組件時(shí),只有props發(fā)生改變子組件才會(huì)重新渲染。使用memo可以提升一定的性能。

          const Child = React.memo((props: any) => {    console.log("我是前端開(kāi)發(fā)愛(ài)好者的子組件,我更新了..."); // 只有當(dāng)props屬性改變,集name屬性改變時(shí),子組件才會(huì)重新渲染    return (        <div>            <h3>子組件</h3>            <div>text:{props.name}</div>            <div>{new Date().getTime()}</div>        </div>    )})const Parent = () => {    const [count, setCount] = useState(0);    const [text, setText] = useState("")    const handleClick = () => {        setCount(count + 1);    }    const handleInputChange = (e) => {        setText(e.target.value)    }    return (<div>        <input onChange={handleInputChange} />        <button onClick={handleClick}>+1</button>         <div>count:{count}</div>        <Child name ={text}/>    </div>)}

          但如果傳入的props包含函數(shù),父組件每次重新渲染都是創(chuàng)建新的函數(shù),所以傳遞函數(shù)子組件還是會(huì)重新渲染,即使函數(shù)的內(nèi)容還是一樣。如何解決這一問(wèn)題,我們希望把函數(shù)也緩存起來(lái),于是引入useCallback


          useCallback

              useCallback用用于緩存函數(shù),只有當(dāng)依賴項(xiàng)改變時(shí),函數(shù)才會(huì)重新執(zhí)行返回新的函數(shù),對(duì)于父組件中的函數(shù)作為props傳遞給子組件時(shí),只要父組件數(shù)據(jù)改變,函數(shù)重新執(zhí)行,作為props的函數(shù)也會(huì)產(chǎn)生新的實(shí)例,導(dǎo)致子組件的刷新
          使用useCallback可以緩存函數(shù)。需要搭配memo使用

          const Child = React.memo((props: any) => {    console.log("我是前端開(kāi)發(fā)愛(ài)好者的子組件,我更新了...");    return (       <div>           <h3>子組件</h3>           <div>text:{props.name}</div>           <div> <input onChange={props.handleInputChange} /></div>           <div>{new Date().getTime()}</div>       </div>   )})const Parent = () => {   const [count, setCount] = useState(0);   const [text, setText] = useState("")   const handleClick = () => {       setCount(count + 1);   }   const handleInputChange = useCallback((e) => {       setText(e.target.value )   },[])    return (<div>       <button onClick={handleClick}>+1</button>       <div>count:{count}</div>       <Child name={text} handleInputChange={handleInputChange}/>   </div>)}

          useCallback第二個(gè)參數(shù)依賴項(xiàng)什么情況下使用呢,看下面的例子

          //修改handleInputChangeconst handleInputChange =useCallback((e) => {        setText(e.target.value + count)    },[])

          以上例子count改變會(huì)發(fā)生什么事呢?
          count改變,但handleInputChange不依賴與任何項(xiàng),所以handleInputChange只在初始化的時(shí)候調(diào)用一次函數(shù)就被緩存起來(lái),當(dāng)文本改變時(shí)或者count改變時(shí)函數(shù)內(nèi)部的count始終為0,至于為什么需要看useCallback源碼后解答。
          所以需要將count加入到依賴項(xiàng),count變化后重新生成新的函數(shù),改變函數(shù)內(nèi)部的count值


          const handleInputChange =useCallback((e) => {        setText(e.target.value + count)    },[count])

          useMemo

              useMemo使用場(chǎng)景請(qǐng)看下面這個(gè)例子,getTotal假設(shè)是個(gè)很昂貴的操作,但該函數(shù)結(jié)果僅依賴于count和price,但是由于color變化,DOM重新渲染也會(huì)導(dǎo)致該函數(shù)的執(zhí)行,useMemo便是用于緩存該函數(shù)的執(zhí)行結(jié)果,僅當(dāng)依賴項(xiàng)改變后才會(huì)重新計(jì)算


          const Parent = () => { const [count, setCount] = useState(0); const [color,setColor] = useState(""); const [price,setPrice] = useState(10); const handleClick = () => { setCount(count + 1); } const getTotal = ()=>{ console.log("getTotal 執(zhí)行了 ...") // 該函數(shù)依賴于count和price,但color變化也會(huì)導(dǎo)致該函數(shù)的執(zhí)行 return count * price } return (<div>
          <div> 顏色: <input onChange={(e) => setColor(e.target.value)}/></div> <div> 單價(jià): <input value={price} onChange={(e) => setPrice(Number(e.target.value))}/></div> <div> 數(shù)量:{count} <button onClick={handleClick}>+1</button></div> <div>總價(jià):{getTotal()}</div> </div>)}

          修改后如下,注意useMemo緩存的是函數(shù)執(zhí)行的結(jié)果

          const Parent = () => {    console.log("parent 執(zhí)行了...")    const [count, setCount] = useState(0);    const [color,setColor] = useState("");    const [price,setPrice] = useState(10);    const handleClick = () => {        setCount(count + 1);    }    const getTotal = useMemo(()=>{        console.log("getTotal 執(zhí)行了 ...")         return count * price    },[count, price])    return (<div>
          <div> 顏色: <input onChange={(e) => setColor(e.target.value)}/></div> <div> 單價(jià): <input value={price} onChange={(e) => setPrice(Number(e.target.value))}/></div> <div> 數(shù)量:{count} <button onClick={handleClick}>+1</button></div> <div>總價(jià):{getTotal}</div> </div>)}

          至此重復(fù)渲染的問(wèn)題的解決基本上可以告一段落。


              在 React 中是極力推薦函數(shù)式編程,可以讓數(shù)據(jù)不可變性作為我們優(yōu)化的手段。我在 React class 時(shí)代大量使用了 immutable.js 結(jié)合 redux 來(lái)搭建業(yè)務(wù),與 React 中 PureComponnet 完美配合,性能保持非常好。但是在 React hooks 中再結(jié)合 typescript 它就顯得有點(diǎn)格格不入了,類型支持得不是很完美。這里可以嘗試一下 immer.js,引入成本小,寫法也簡(jiǎn)潔了不少。


              最后推薦一個(gè)比較好用的 hooks 庫(kù) :ahooks : https://ahooks.js.org/zh-CN/hooks/async

               ahooks 是一個(gè) React Hooks 庫(kù),致力提供常用且高質(zhì)量的 Hooks。針對(duì)性能優(yōu)化也提供了相應(yīng)的hooks, 例如 : usePersistFn  useCreation ...

              更多 hooks 的使用自行查看官方文檔吧,這里就不做過(guò)多的介紹了。 


          往期推薦

          React Hooks使用心得!真香

          前端開(kāi)發(fā)者應(yīng)該知道的 Centos/Docker/Nginx/Node/Jenkins 操作

          百度統(tǒng)計(jì)分析埋點(diǎn)最佳實(shí)戰(zhàn)篇

          Mapbox 3D 衛(wèi)星地圖帶你領(lǐng)略環(huán)法自行車騎行,那飛一般的感覺(jué)!

          Vue3 全家桶 + TS+ Vite2 + element-plus 搭建簡(jiǎn)潔時(shí)尚的博客網(wǎng)站實(shí)戰(zhàn)及踩坑記



          瀏覽 48
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  围产精品久久久久久久黄无码 | 特级AV免费在线观看 | 欧美日本视频在线观看 | 美女操逼视频。 | 国产成人性爱视频 |