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

React避免子組件無(wú)效刷新的三種解決方案

 更新時(shí)間:2023年08月01日 08:39:08   作者:sorryhc  
這篇文章主要給大家介紹了React三種避免子組件無(wú)效刷新的解決方案,使用React.memo,使用React.useMemo或React.useCallback,將子組件作為children來(lái)傳遞這三種方案,文章通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下

前言

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

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

舉個(gè)簡(jiǎn)單的例子:

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組件沒(méi)有接收來(lái)自父組件的值,每次點(diǎn)擊父組件元素讓name更新,Child組件會(huì)更新嗎?答案是會(huì)的,你一定會(huì)好奇,子組件沒(méi)有接收任何的props,為什么也會(huì)更新呢?

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

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

const oldProps = current.memoizedProps; // 更新前老的props
const newProps = workInProgress.pendingProps; // 待比較更新后的props
if (oldProps !== newProps) {
  didReceiveUpdate = true; // 標(biāo)記為發(fā)生變化,需要更新
}

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

  • 使用React.memo,可以指定在Diff時(shí)對(duì)于被memo包裹的組件只做淺層比較;
  • 使用React.useMemoReact.useCallback來(lái)包住子組件,讓每次更新子組件都為同一個(gè)JSX對(duì)象,這也props的比較就會(huì)相同;
  • 將子組件作為children來(lái)傳遞;

React.memo

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

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

源碼如下:

 function shallowEqual(objA: mixed, objB: mixed): boolean {
  // 一樣的對(duì)象返回true
  if (Object.is(objA, objB)) {
    return true;
  }
  // 不是對(duì)象或者為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;
  }
  // 對(duì)應(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的實(shí)現(xiàn)原理很簡(jiǎn)單,對(duì)應(yīng)著上述四種策略。

React.useMemo & React.useCallBack

對(duì)于方案2,如果你不了解React.useMemoReact.useCallback,沒(méi)有關(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接收兩個(gè)參數(shù),第一個(gè)參數(shù)為返回值,第二個(gè)參數(shù)為依賴項(xiàng),當(dāng)依賴項(xiàng)數(shù)組中的值發(fā)生變化,則返回值會(huì)重新計(jì)算,也就是說(shuō)第二個(gè)依賴項(xiàng)傳空數(shù)組,則依賴項(xiàng)永遠(yuǎn)都不會(huì)發(fā)生變化,則Child組件經(jīng)過(guò)React.useMemo包裹后一直不會(huì)被React去計(jì)算Diff,就實(shí)現(xiàn)了父組件更新,子組件不觸發(fā)更新。

但對(duì)于React.useMemo的使用,如果傳給了子組件的值,但是未聲明依賴項(xiàng),會(huì)導(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為改變依賴項(xiàng),因此當(dāng)name發(fā)生變化,子組件依然會(huì)永遠(yuǎn)返回初始值1,因此對(duì)于React.useMemo的緩存策略在優(yōu)化時(shí)也需要充分考慮意外事故發(fā)生。

向上提煉 & 向下移動(dòng)

對(duì)于方案3,可以簡(jiǎn)單理解成向上提煉和向下移動(dòng)state,先看一個(gè)案例:

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>
  );
};

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

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

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

還有一種解法就是狀態(tài)提升,我們可以把這段性能消耗嚴(yán)重的代碼同樣單獨(dú)封裝成一個(gè)組件,將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>
  );
};

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

結(jié)尾

本文主要記錄了博主在日常開(kāi)發(fā)用到比較多的三種優(yōu)化策略,微笑的細(xì)節(jié)差帶來(lái)的優(yōu)化提升手段,希望對(duì)你有幫助哦~

以上就是React避免子組件無(wú)效刷新的三種解決方案的詳細(xì)內(nèi)容,更多關(guān)于React避免子組件無(wú)效刷新的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 基于React編寫(xiě)一個(gè)全局Toast的示例代碼

    基于React編寫(xiě)一個(gè)全局Toast的示例代碼

    前些日子在做項(xiàng)目的時(shí)候,需要封裝一個(gè)Toast組件,我想起之前用過(guò)的庫(kù),只要在入口文件中引入就可以在全局中使用,還是很方便的,借這次機(jī)會(huì)也來(lái)實(shí)現(xiàn)一下,所以本文介紹了React中如何編寫(xiě)一個(gè)全局Toast,需要的朋友可以參考下
    2024-05-05
  • React hook超詳細(xì)教程

    React hook超詳細(xì)教程

    Hook是React16.8的新增特性。它可以讓你在不編寫(xiě)class的情況下使用state以及其他的React特性,這篇文章主要介紹了React hook的使用
    2022-10-10
  • 詳解前端路由實(shí)現(xiàn)與react-router使用姿勢(shì)

    詳解前端路由實(shí)現(xiàn)與react-router使用姿勢(shì)

    本篇文章主要介紹了詳解前端路由和react-router使用姿勢(shì),詳細(xì)的介紹了react-router的用法,有興趣的可以了解一下
    2017-08-08
  • React RenderProps模式超詳細(xì)講解

    React RenderProps模式超詳細(xì)講解

    render props是指一種在 React 組件之間使用一個(gè)值為函數(shù)的 prop 共享代碼的技術(shù)。簡(jiǎn)單來(lái)說(shuō),給一個(gè)組件傳入一個(gè)prop,這個(gè)props是一個(gè)函數(shù),函數(shù)的作用是用來(lái)告訴這個(gè)組件需要渲染什么內(nèi)容,那么這個(gè)prop就成為render prop
    2022-11-11
  • React中Suspense及l(fā)azy()懶加載及代碼分割原理和使用方式

    React中Suspense及l(fā)azy()懶加載及代碼分割原理和使用方式

    這篇文章主要介紹了React中Suspense及l(fā)azy()懶加載及代碼分割原理和使用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-09-09
  • 用react-redux實(shí)現(xiàn)react組件之間數(shù)據(jù)共享的方法

    用react-redux實(shí)現(xiàn)react組件之間數(shù)據(jù)共享的方法

    這篇文章主要介紹了用react-redux實(shí)現(xiàn)react組件之間數(shù)據(jù)共享的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-06-06
  • react實(shí)現(xiàn)消息顯示器

    react實(shí)現(xiàn)消息顯示器

    這篇文章主要為大家詳細(xì)介紹了react實(shí)現(xiàn)消息顯示器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-08-08
  • 基于Node的React圖片上傳組件實(shí)現(xiàn)實(shí)例代碼

    基于Node的React圖片上傳組件實(shí)現(xiàn)實(shí)例代碼

    本篇文章主要介紹了基于Node的React圖片上傳組件實(shí)現(xiàn)實(shí)例代碼,非常具有實(shí)用價(jià)值,需要的朋友可以參考下
    2017-05-05
  • React循環(huán)遍歷渲染數(shù)組和對(duì)象元素方式

    React循環(huán)遍歷渲染數(shù)組和對(duì)象元素方式

    這篇文章主要介紹了React循環(huán)遍歷渲染數(shù)組和對(duì)象元素方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-09-09
  • React函數(shù)組件和類(lèi)組件的區(qū)別及說(shuō)明

    React函數(shù)組件和類(lèi)組件的區(qū)別及說(shuō)明

    這篇文章主要介紹了React函數(shù)組件和類(lèi)組件的區(qū)別及說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-08-08

最新評(píng)論

东宁县| 涿鹿县| 安远县| 尼勒克县| 赫章县| 洪江市| 芦溪县| 休宁县| 周口市| 东丰县| 泰州市| 乌苏市| 阳江市| 永川市| 大连市| 大冶市| 伊春市| 青田县| 疏勒县| 南木林县| 黑山县| 无棣县| 永胜县| 巴马| 库伦旗| 江山市| 泗阳县| 襄垣县| 鹿邑县| 乐亭县| 博野县| 金阳县| 邵阳县| 塔河县| 秦安县| 如东县| 中西区| 仁化县| 凤城市| 资阳市| 苍山县|