最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

React如何避免子組件無效刷新

 更新時間:2024年03月14日 10:43:03   作者:C+ 安口木  
這篇文章主要介紹了React幾種避免子組件無效刷新的解決方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教

React如何避免子組件無效刷新

一個很常見的場景,React中父組件和子組件在一起,子組件不依賴于父組件任何數(shù)據(jù),但是會一起發(fā)生變化。

在探究原理之前,先回憶一下,React中的Diff算法會將更新前后的兩棵虛擬DOM樹做對比,但這并不會決定組件是否更新,只會決定是否要復(fù)用老的節(jié)點。

舉個簡單的例子:

import { useState } from 'react';

const Child = () => {
  console.log('child render');

  return null;
};

const App = () => {
  const [name, setName] = useState(1);

  return (
    <div onClick={() => setName(2)}>
      <Child />
    </div>
  );
};

Child組件沒有接收來自父組件的值,每次點擊父組件元素讓name更新,Child組件會更新嗎?答案是會的,你一定會好奇,子組件沒有接收任何的props,為什么也會更新呢?

首先,父組件經(jīng)過了Diff階段,會判斷Child組件是否發(fā)生變化,在本案例中Child內(nèi)部的元素結(jié)構(gòu)和狀態(tài)無任何變化,React還會對比Child組件前后的props是否相同,在本案例中,前后props不相同。

說到這里,你一定忍不住了,我都沒傳props,為啥不相同?原因是React內(nèi)部對于props的對比只進行了淺層比較,通過 !== 來判斷,這樣即使沒傳props,每次生成的props對象都是新的指針,即使為空,也會生成不同的props空對象,就像這樣:

typescript復(fù)制代碼const oldProps = current.memoizedProps; // 更新前老的props

const newProps = workInProgress.pendingProps; // 待比較更新后的props

if (oldProps !== newProps) {
  didReceiveUpdate = true; // 標記為發(fā)生變化,需要更新
}

那有什么方法可以避免這樣的無效更新呢?一共有三種方案。

  • 使用React.memo,可以指定在Diff時對于被memo包裹的組件只做淺層比較;
  • 使用React.useMemo或React.useCallback來包住子組件,讓每次更新子組件都為同一個JSX對象,這也props的比較就會相同;
  • 將子組件作為children來傳遞;

React.memo

對于方案1,React.memo的原理其實來源于源碼中的shallowEqual函數(shù),該函數(shù)會接收兩個對象,分別對應(yīng)老的props和新的props,一共有四種比較策略,如果四種策略都通過,則判定新舊為同一個對象,不做更新,復(fù)用老的節(jié)點。

  • 判斷兩者是否為同一對象,不是同一對象則返回false;
  • 判斷兩者的值不為object或為null,則返回false;
  • 對比兩者key的數(shù)量,不一致則返回false;
  • 對比兩者key的值是否相同,不一致則返回false;

源碼如下:

function shallowEqual(objA: mixed, objB: mixed): boolean {
  // 一樣的對象返回true

  if (Object.is(objA, objB)) {
    return true;
  }

  // 不是對象或者為null返回false

  if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) {
    return false;
  }

  const keysA = Object.keys(objA);

  const keysB = Object.keys(objB);

  // key數(shù)量不同返回false

  if (keysA.length !== keysB.length) {
    return false;
  }

  // 對應(yīng)key的值不相同返回false

  for (let i = 0; i < keysA.length; i++) {
    if (!hasOwnProperty.call(objB, keysA[i]) || !Object.is(objA[keysA[i]], objB[keysA[i]])) {
      return false;
    }
  }

  return true;
}

可以看到淺比較props的實現(xiàn)原理很簡單,對應(yīng)著上述四種策略。

React.useMemo & React.useCallBack

對于方案2,如果你不了解React.useMemo和React.useCallback,沒有關(guān)系,先看一下這段代碼塊:

import { useMemo } from 'react';

const Child = () => {
  console.log('child render');

  return null;
};

const App = () => {
  const [name, setName] = useState(1);

  const child = useMemo(() => <Child />, []);

  return <div onClick={() => setName(2)}>{child}</div>;
};

React.useMemo接收兩個參數(shù),第一個參數(shù)為返回值,第二個參數(shù)為依賴項,當依賴項數(shù)組中的值發(fā)生變化,則返回值會重新計算,也就是說第二個依賴項傳空數(shù)組,則依賴項永遠都不會發(fā)生變化,則Child組件經(jīng)過React.useMemo包裹后一直不會被React去計算Diff,就實現(xiàn)了父組件更新,子組件不觸發(fā)更新。

但對于React.useMemo的使用,如果傳給了子組件的值,但是未聲明依賴項,會導(dǎo)致子組件一直不發(fā)生變化,就像這樣:

import { useMemo } from 'react';

const Child = ({ name }) => {
  console.log('child render');

  return name;
};

const App = () => {
  const [name, setName] = useState(1);

  const child = useMemo(() => <Child name={name} />, []);

  return <div onClick={() => setName(2)}>{child}</div>;
};

像這種情況,父組件將name傳給了子組件,但是由于子組件未聲明name為改變依賴項,因此當name發(fā)生變化,子組件依然會永遠返回初始值1,因此對于React.useMemo的緩存策略在優(yōu)化時也需要充分考慮意外事故發(fā)生。

向上提煉 & 向下移動

對于方案3,可以簡單理解成向上提煉和向下移動state,先看一個案例:

const App = () => {
  const [color, setColor] = useState('red');

  return (
    <div>
      <input value={color} onChange={(e) => setColor(e.target.value)} />

      <p style={{ color }}>Hello, world!</p>

      <Child />
    </div>
  );
};

Input的onChange事件是一個頻繁觸發(fā)的顏色指示器,一秒會觸發(fā)上百次,而Child組件是一個固定渲染不依賴父組件狀態(tài)的子組件,如何通過狀態(tài)向下移動的方式來避免Child組件被渲染呢?

const App = () => {
  return (
    <div>
      <Form />
      <Child />
    </div>
  );
};

我們只需要將這段性能消耗大的代碼抽離到單獨的一個Form組件中,同時把color狀態(tài)單獨交給Form組件去管理,這樣App父組件一直沒有發(fā)生重渲染,Child子組件也不會被影響,只有Form子組件在單獨發(fā)生交互,這種方案更像是一個狀態(tài)下移 + 隔離。

還有一種解法就是狀態(tài)提升,我們可以把這段性能消耗嚴重的代碼同樣單獨封裝成一個組件,將Child子組件的內(nèi)容傳遞給Form子組件,就像這樣:

const Form = ({ children }) => {
  const [color, setColor] = useState('red');

  return (
    <div style={{ color }}>
      <input value={color} onChange={(e) => setColor(e.target.value)} />

      {children}
    </div>
  );
};

const App = () => {
  return (
    <div>
      <Form>
        <p>Hello, world</p>
        <Child />
      </Form>
    </div>
  );
};

其實思路是和狀態(tài)向下提升是一樣的,把性能消耗嚴重的一部分單獨抽離到一個組件中,將相對不期望被影響的一部分通過特定形式渲染,因此Child子組件在這種情況也不會被重新渲染。

React強制刷新子組件方法

給子組件打個key值

每次操作更新個key就好了

總結(jié)

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • react的ui庫antd中form表單使用SelectTree反顯問題及解決

    react的ui庫antd中form表單使用SelectTree反顯問題及解決

    這篇文章主要介紹了react的ui庫antd中form表單使用SelectTree反顯問題及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-01-01
  • react如何修改循環(huán)數(shù)組對象的數(shù)據(jù)

    react如何修改循環(huán)數(shù)組對象的數(shù)據(jù)

    這篇文章主要介紹了react如何修改循環(huán)數(shù)組對象的數(shù)據(jù)問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-12-12
  • es6在react中的應(yīng)用代碼解析

    es6在react中的應(yīng)用代碼解析

    這篇文章主要介紹了es6在react中的應(yīng)用代碼解析,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2017-11-11
  • react組件傳值的四種方法

    react組件傳值的四種方法

    本文主要介紹了react組件傳值的四種方法,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • React進行路由變化監(jiān)聽的解決方案

    React進行路由變化監(jiān)聽的解決方案

    在現(xiàn)代單頁應(yīng)用(SPA)中,路由管理是至關(guān)重要的一部分,它不僅決定了用戶如何在頁面間切換,還直接影響到整個應(yīng)用的性能和用戶體驗,這些看似不起眼的問題,往往會導(dǎo)致功能錯亂和性能下降,本篇文章將深入探討在 React 中如何高效監(jiān)聽路由變化,需要的朋友可以參考下
    2025-01-01
  • 淺析history 和 react-router 的實現(xiàn)原理

    淺析history 和 react-router 的實現(xiàn)原理

    react-router 版本更新非???但是它的底層實現(xiàn)原理確是萬變不離其中,在本文中會從前端路由出發(fā)到 react-router 原理總結(jié)與分享,本文對history 和 react-router實現(xiàn)原理講解的非常詳細,需要的朋友跟隨小編一起看看吧
    2023-08-08
  • 關(guān)于react hook useState連續(xù)更新對象的問題

    關(guān)于react hook useState連續(xù)更新對象的問題

    這篇文章主要介紹了關(guān)于react hook useState連續(xù)更新對象的問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • 列表頁常見hook封裝實例

    列表頁常見hook封裝實例

    這篇文章主要為大家介紹了列表頁常見的hook封裝示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-07-07
  • React?之最小堆min?heap圖文詳解

    React?之最小堆min?heap圖文詳解

    這篇文章主要為大家介紹了React?之最小堆min?heap圖文詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-11-11
  • React如何避免重渲染

    React如何避免重渲染

    這篇文章主要介紹了React如何避免重渲染,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-04-04

最新評論

绥滨县| 三都| 积石山| 伊春市| 达尔| 隆安县| 丰城市| 绥中县| 盖州市| 紫云| 黄冈市| 永济市| 渑池县| 西平县| 淮南市| 高碑店市| 吴川市| 阜平县| 淄博市| 福建省| 维西| 元江| 肥乡县| 建昌县| 乳山市| 大竹县| 江都市| 盐亭县| 谷城县| 文安县| 黄浦区| 香河县| 彭阳县| 邵东县| 竹溪县| 东至县| 商都县| 胶州市| 应用必备| 长顺县| 北京市|