<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中的re-render問(wèn)題

          共 7106字,需瀏覽 15分鐘

           ·

          2022-01-15 23:28

          開(kāi)頭

          大家好,我是Peter,React中的一個(gè)re-render問(wèn)題,相信很多人都遇到過(guò)。接下來(lái)給大家具體講講這個(gè)問(wèn)題

          re-render?

          首先使用我的腳手架

          npm i ykj-cli -g 
          ykj init App
          cd ./app
          yarn 
          yarn dev

          這樣一個(gè)webpack5、TS、React項(xiàng)目就搭建好了

          我們目前只有一個(gè)APP組件,內(nèi)部代碼:

          import Myy from './myy.jpg';

          function App() {
              console.log('render')
              return (
                  <div className="app">
                      <h1>歡迎使用明源云 - 云空間前端通用腳手架</h1>
                      <img src={Myy} alt="" style={{ width: 500, height: 500 }} />
                      <h4>
                          加入我們:<a>[email protected]</a>
                      </h4>
                      <h4>微前端,webpack5,TypeScript,React,vite應(yīng)有盡有</h4>
                  </div>
              );
          }

          export default App;

          刷新訪問(wèn)頁(yè)面后,發(fā)現(xiàn)控制臺(tái)只打印了一次

          OK,那我們正式開(kāi)始,加入一些狀態(tài),以及新增一個(gè)按鈕和SubApp組件

          import { useState } from 'react';
          import Myy from './myy.jpg';
          import SubApp from './SubApp'
          function App() {
              const [state, setState] = useState("Peter");
              return (
                  <div className="app">
                      <h1>歡迎使用明源云 - 云空間前端通用腳手架</h1>
                      <img src={Myy} alt="" style={{ width: 500, height: 500 }} />
                      <h4>
                          加入我們:<a>[email protected]</a>
                      </h4>
                      <SubApp state={state} />
                      <h4>微前端,webpack5,TypeScript,React,vite應(yīng)有盡有</h4>
                      <button onClick={() => {
                          setState('關(guān)注公眾號(hào):前端巔峰')
                      }}>測(cè)試按鈕</button>
                  </div>
              );
          }

          export default App;


          //SubApp組件
          function SubApp({ state }) {
              console.log('render')
              return <h1>{state}</h1>
          }

          export default SubApp

          這個(gè)時(shí)候點(diǎn)擊按鈕,又觸發(fā)了一次render

          那么接下來(lái)我們繼續(xù)點(diǎn)擊按鈕,看是否會(huì)繼續(xù)render

          多次點(diǎn)擊,發(fā)現(xiàn)render只有一次,因?yàn)槲覀兇藭r(shí)每次點(diǎn)擊都是將state的值變成:關(guān)注公眾號(hào):前端巔峰這個(gè)字符串。

          那么,我們嘗試著將state變成一個(gè)對(duì)象

          const [state, setState] = useState({ des: "Peter" });
            <button onClick={() => {
                          setState({ des: '關(guān)注公眾號(hào):前端巔峰' })
                      }}>測(cè)試按鈕</button>

          神奇的事情發(fā)生了,這里每次點(diǎn)擊設(shè)置同樣的state,都會(huì)觸發(fā)子組件render. - 這里就出現(xiàn)了re-render問(wèn)題,我們其實(shí)都是拿的同樣的state,但是卻出現(xiàn)了不必要的render

          錯(cuò)誤的優(yōu)化

          很多同學(xué)在使用React過(guò)程中會(huì)錯(cuò)誤的使用PureComponent和useEffect以及UseMemo.

          這里我們先用錯(cuò)誤的方式引入useEffect,改造SubApp

          import React, { useEffect, useState } from 'react';

          function SubApp({ state }) {
              const [data, setData] = useState({})
              useEffect(() => {
                  console.log('render')
                  setData(state)
              }, [state])
              console.log('render')
              return <h1>{data.des}</h1>
          }

          export default SubApp

          這里可以看到,每次點(diǎn)擊按鈕都在不斷render,使用了useEffect竟然失效了。這優(yōu)化無(wú)效~

          這里就要談到useEffect的源碼實(shí)現(xiàn),其實(shí)useEffect和PureComponent等一系列優(yōu)化手段,大都是使用了Object.is()這個(gè)算法。

          MDN資料地址:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/is

          Object.is

          • Object.is() 方法判斷兩個(gè)值是否為同一個(gè)值。
          value1
          被比較的第一個(gè)值。
          value2
          被比較的第二個(gè)值。
          返回值
          一個(gè) Boolean 類型標(biāo)示兩個(gè)參數(shù)是否是同一個(gè)值。

          描述
          Object.is() 方法判斷兩個(gè)值是否為同一個(gè)值。如果滿足以下條件則兩個(gè)值相等:

          都是 undefined
          都是 null
          都是 true 或 false
          都是相同長(zhǎng)度的字符串且相同字符按相同順序排列
          都是相同對(duì)象(意味著每個(gè)對(duì)象有同一個(gè)引用)
          都是數(shù)字且
          都是 +0
          都是 -0
          都是 NaN
          或都是非零而且非 NaN 且為同一個(gè)值
          與== (en-US) 運(yùn)算不同。== 運(yùn)算符在判斷相等前對(duì)兩邊的變量(如果它們不是同一類型) 進(jìn)行強(qiáng)制轉(zhuǎn)換 (這種行為的結(jié)果會(huì)將 "" == false 判斷為 true), 而 Object.is不會(huì)強(qiáng)制轉(zhuǎn)換兩邊的值。

          與=== (en-US) 運(yùn)算也不相同。=== 運(yùn)算符 (也包括 == 運(yùn)算符) 將數(shù)字 -0 和 +0 視為相等 ,而將Number.NaN 與NaN視為不相等.

          合理使用useEffect,解決re-render

          如果Props傳入的是一個(gè)對(duì)象,那么由于React hooks每次更新都會(huì)生成一個(gè)全新的對(duì)象,而這個(gè)全新的對(duì)象和之前的對(duì)象,無(wú)法通過(guò)Object.is去對(duì)比,每次都會(huì)不相等。例如:

            const obj1 = {
                      name: "peter"
                  }
                  const obj2 = {
                      name: "peter"
                  }

                  console.log(Object.is(obj1, obj2, 'xx'))

          這段代碼永遠(yuǎn)輸出都是false,因?yàn)閛bj1和obj2是兩個(gè)不同地址的引用對(duì)象

          但是如果我們換一種方式:

          Object.is(obj1.name, obj2.name )

          這樣就可以正常比較,永遠(yuǎn)輸出ture

          那么我們現(xiàn)在也要在useEffect中類似這樣使用

              useEffect(() => {
                  setData(state)
                  console.log('render')
              }, [state.des])

          這樣我們的useEffect內(nèi)部回調(diào)只會(huì)被觸發(fā)一次

          加餐,簡(jiǎn)單實(shí)現(xiàn)useEffect

          網(wǎng)上抄的代碼改造了比較方法

          let _deps;
          function useEffect(callback, dependencies) {
            const hasChanged = _deps
              && !dependencies.every((el, i) =>Object.is( el ,_deps[i]))
              || true;
            // 如果 dependencies 不存在,或者 dependencies 有變化,就執(zhí)行 callback
            if (!dependencies || hasChanged) {
              callback();
              _deps = dependencies;
            }
          }

          實(shí)現(xiàn)邏輯:將傳入的依賴項(xiàng)遍歷,通過(guò)Object.is方法與原依賴項(xiàng)的值進(jìn)行淺對(duì)比,如果不一致就執(zhí)行callback。

          結(jié)語(yǔ)

          所以大家在解決re-render問(wèn)題時(shí),或者使用useEffect之類優(yōu)化方案時(shí),應(yīng)該監(jiān)聽(tīng)對(duì)比某個(gè)值,而不是去監(jiān)聽(tīng)某個(gè)大對(duì)象進(jìn)行對(duì)比。相信這篇文章能解決你心中疑惑很久的re-render問(wèn)題,如果感覺(jué)寫(xiě)得不錯(cuò)的話,幫忙來(lái)個(gè)贊、在看、轉(zhuǎn)發(fā)三連

          結(jié)語(yǔ)

          「關(guān)注公眾號(hào)IQ前端,一個(gè)專注于CSS/JS開(kāi)發(fā)技巧的前端公眾號(hào),更多前端小干貨等著你喔」



          瀏覽 47
          點(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>
                  久久久久99精品成人片毛片 | 亚洲人成无码网ww在线观看 | 久久久久久久久成人电影 | 国产女同视频 | 青草人人操|