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

react?context優(yōu)化四重奏教程示例

 更新時間:2022年10月26日 16:20:19   作者:刁民hero  
這篇文章主要為大家介紹了react?context優(yōu)化四重奏教程示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

一、前言

我們在使用react的過程中,經(jīng)常會遇到需要跨層級傳遞數(shù)據(jù)的情況。props傳遞數(shù)據(jù)應(yīng)用在這種場景下會極度繁瑣,且不利于維護,于是context應(yīng)運而生

官方解釋: Context 提供了一種在組件之間共享此類值的方式,而不必顯式地通過組件樹的逐層傳遞 props

二、用法

在正文之前,先簡單介紹一下context的三種消費方法:

  • 1.通過Consumer來消費上下文
const globalContext = React.createContext();
class TestUseContextSon1 extends React.Component {
  render() {
    return (
      <globalContext.Consumer>
        {(value) => {
          return <div>{value.num}</div>;
        }}
      </globalContext.Consumer>
    );
  }
}
export default class TestUseContext extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      num: 2,
    };
  }
  render() {
    return (
      <globalContext.Provider value={{ num: this.state.num }}>
        <TestUseContextSon1 />
      </globalContext.Provider>
    );
  }
}
  • 2.通過靜態(tài)變量contextType來消費上下文
const globalContext = React.createContext();
class TestUseContextSon2 extends React.Component {
  static contextType = globalContext;
  render() {
    return <div>{this.context.num}</div>;
  }
}
export default class TestUseContext extends React.Component {
  ...省略...
  render() {
    return (
      <globalContext.Provider value={{ num: this.state.num }}>
        <TestUseContextSon2 />
      </globalContext.Provider>
    );
  }
}
  • 3.通過hooks useContext來消費上下文
const globalContext = React.createContext();
const TestUseContextSon3 = (props) => {
  const con = useContext(globalContext);
  return <div>{con.num}</div>;
};
export default class TestUseContext extends React.Component {
  ...省略...
  render() {
    return (
      <globalContext.Provider value={{ num: this.state.num }}>
        <TestUseContextSon3 />
      </globalContext.Provider>
    );
  }
}

比較:

  • Consumer既可以在類組件中使用,也可以在函數(shù)組件中使用
  • contextType只能在類組件中使用
  • useContext只能在函數(shù)組件中使用

三、缺點

這里有一個例子:

import React, { useState } from "react";
const globalContext = React.createContext();
const Son1 = () => {
  return <div>Son1</div>;
};
const Son2 = () => {
  const value = useContext(globalContext);
  return <div>Son2---{value.num}</div>;
};
export const Demo = () => {
  const [value, setValue] = useState({ num: 1 });
  return (
    <globalContext.Provider value={value}>
      <Son1 />
      <Son2 />
    </globalContext.Provider>
  );
};

當(dāng)我們改變value值時,會導(dǎo)致Son1、Son2都發(fā)生重渲染,但這與我們的初衷相悖,造成了額外的開銷,我們期望做到的是Son1不執(zhí)行,Son2重新渲染。在較長的一段時間內(nèi),我都認(rèn)為是使用了context導(dǎo)致Provider下面的子組件發(fā)生了重渲染。網(wǎng)上也有很多解釋沒有說清楚,容易誤導(dǎo)人。

實際情況是value的變化導(dǎo)致了Son1Son2發(fā)生重渲染。如下示例: 即使我們不使用·context,當(dāng)value發(fā)生變化時,Son1、Son2也會重渲染。

const Son1 = () => {
  return <div>Son1</div>;
};
const Son2 = () => {
  return <div>Son2</div>;
};
export const Demo = () => {
  const [value, setValue] = useState({ num: 1 });
  return (
    <Son1 />
    <Son2 />
  );
};

那么問題來了,我們使用context的時候,必然要向<globalContext.Provider value={value}>Provider的value中傳入一個狀態(tài),但是當(dāng)狀態(tài)改變時又不可避免的造成Provider下的所有子組件重新渲染,我們期望只有消費了上下文的子組件重新渲染,那么有什么方法能夠避免這種額外的開銷嗎?

四、context優(yōu)化

我們知道,所有消費了context的地方,只要Providervalue值發(fā)生變化,都會發(fā)生重渲染.只要我們有什么辦法能夠避開父組件狀態(tài)發(fā)生變化,引起的子組件狀態(tài)發(fā)生變化,那就可以減少很多不必要的開銷。

一重奏--使用PureComponent

const globalContext = React.createContext();
class TestUseContextSon2 extends React.PureComponent {
  constructor(props) {
    super(props);
    this.state = {};
  }
  render() {
    console.log("TestUseContextSon2----render");
    return (
      <globalContext.Consumer>
        {(value) => {
          console.log("Consumer----handle");
          return <div>{value.num}</div>;
        }}
      </globalContext.Consumer>
    );
  }
}
const TestUseContext = () => {
  const [value, setValue] = useState({ num: 1 });
  return (
      <globalContext.Provider value={value}>
        <button onClick={() => setValue({ num: value.num + 1 })}>
          點擊
        </button>
        <TestUseContextSon2 />
      </globalContext.Provider>
  );
}

初始化的時候,兩個console各執(zhí)行一遍

點擊按鈕之后,TestUseContextSon2----render沒有打印,Consumer----handle打印,達到預(yù)期結(jié)果。

二重奏--使用shouldComponentUpdate

此處由于作者比較任性,省略100字,基本效果其實和PureComponent一致,不做過多描述。

三重奏--使用React.memo

React.memo既可以用于函數(shù)組件,也可以用于類組件

const globalContext = React.createContext();
const TestUseContextSon3 = React.memo(function (props) {
  console.log("TestUseContextSon3----render");
  return (
      <globalContext.Consumer>
        {(value) => {
          console.log("Consumer----handle");
          return <div>{value.num}</div>;
        }}
      </globalContext.Consumer>
    );
});
const TestUseContext = () => {
  const [value, setValue] = useState({ num: 1 });
  return (
      <globalContext.Provider value={value}>
        <button onClick={() => setValue({ num: value.num + 1 })}>
          點擊
        </button>
        <TestUseContextSon3 />
      </globalContext.Provider>
  );
}

點擊按鈕之后,TestUseContextSon2----render沒有打印,Consumer----handle打印,達到預(yù)期結(jié)果。 那如果我們使用useContext來消費上下文呢?

const TestUseContextSon4 = React.memo(function (props) {
  const con = useContext(globalContext);
  console.log("TestUseContextSon4----render");
  return &lt;div&gt;{con.num}&lt;/div&gt;;
});

點擊按鈕之后,TestUseContextSon4----render打印,也就是說當(dāng)我們使用useContext來消費上下文的時候,整個函數(shù)組件會重新執(zhí)行。而Consumer僅僅只是局部執(zhí)行,這意味更少的性能消耗。

四重奏--Provider再封裝+props.children

上面所述的三種方法都存在一個弊端,Provider的直接下級組件都需要用memo、PureComponent、shouldComponentUpdate處理,才能屏蔽掉父級狀態(tài)變化帶來的影響,那么有沒有一種更方便的方式呢?

代碼如下:

/** 主題 */
const ThemeContext = React.createContext({ theme: "red" });
const ThemeProvider = (props) => {
  const [theme, setTheme] = useState({ theme: "red" });
  console.log("ThemeProvider-----", theme.theme);
  return (
    <ThemeContext.Provider value={{ theme, setTheme }}>
      {props.children}
    </ThemeContext.Provider>
  );
};
const Son1 = function (props) {
  const { setTheme } = useContext(ThemeContext);
  return <button onClick={() => setTheme({ theme: "blue" })}>改變主題</button>;
};
const Son2 = function (props) {
  const { theme } = useContext(ThemeContext);
  console.log("Son2----", theme.theme);
  return <div>主題----{theme.theme}</div>;
};
const Son4 = function (props) {
  console.log("Son4---沒有使用上下文");
  return <div>沒有使用上下文</div>;
};
export default class ContextChildren extends React.Component {
  render() {
    return (
      <ThemeProvider>
        <Son1 />
        <Son2 />
        <Son4 />
      </ThemeProvider>
    );
  }
}

在上面這段代碼中,<Son1 />、<Son2 />、<Son3 />并沒有直接放到ThemeContext.Provider組件下面,而是將該組件再次封裝成ThemeProvider組件,并將狀態(tài)管理也放在ThemeProvider組件中,然后通過props.children來引入組件子節(jié)點。

效果如下:

當(dāng)我們點擊按鈕時,打印如下:

點擊按鈕,setTheme執(zhí)行,狀態(tài)由{ theme: "red" }變?yōu)?code>{ theme: "blue" },引起ThemeProvider組件重新執(zhí)行,打印ThemeProvider----- blue,組件Son2由于消費了上下文,重新執(zhí)行,打印Son2---- blue

那么問題來了,為什么沒有打印Son4呢?我們沒有使用memo、PureComponent等處理Son4組件,但是它確實不會重新執(zhí)行。

出現(xiàn)這種現(xiàn)象,其實是props.children引起的,props.children指向一個對象,這個對象中存放著<Son1 /><Son2 />、<Son3 />執(zhí)行的結(jié)果,ThemeProvider執(zhí)行的時候,props.children指向的對象沒有發(fā)生變化,只有當(dāng)ContextChildren組件重新渲染的時候,<Son1 />、<Son2 /><Son3 />才會重新執(zhí)行,由于我們將狀態(tài)放置于ThemeProvider組件中,所以ContextChildren組件不會重新渲染,<Son1 /><Son2 />、<Son3 />也就不會重新執(zhí)行,所以Son4---沒有使用上下文沒有打印。

那如果將ThemeProvider組件改成這樣呢?

const ThemeProvider = (props) => {
  const [theme, setTheme] = useState({ theme: "red" });
  console.log("ThemeProvider-----", theme.theme);
  const content = React.Children.map(props.children, (child) => {
    return child;
  });
  return (
    <ThemeContext.Provider value={{ theme, setTheme }}>
      {content}
    </ThemeContext.Provider>
  );
};

Son4依然沒有執(zhí)行

再改一下:

const ThemeProvider = (props) => {
  const [theme, setTheme] = useState({ theme: "red" });
  console.log("ThemeProvider-----", theme.theme);
  const content = React.Children.map(props.children, (child) => {
    return React.cloneElement(child);
  });
  return (
    <ThemeContext.Provider value={{ theme, setTheme }}>
      {content}
    </ThemeContext.Provider>
  );
};

我們使用React.cloneElementapi克隆一下child

Son4執(zhí)行了,我想這是因為克隆之后指向發(fā)生變化,導(dǎo)致組件重新執(zhí)行

總結(jié)

本文簡單介紹了一下context的幾種用法,以及如何來屏蔽父級狀態(tài)變化(provider的value一般是和父級組件狀態(tài)掛鉤的)導(dǎo)致未消費上下文的子組件重新渲染導(dǎo)致的額外開銷。

以上就是react context優(yōu)化四重奏教程示例的詳細(xì)內(nèi)容,更多關(guān)于react context 優(yōu)化教程的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 詳解react-router4 異步加載路由兩種方法

    詳解react-router4 異步加載路由兩種方法

    本篇文章主要介紹了詳解react-router4 異步加載路由兩種方法 ,具有一定的參考價值,有興趣的可以了解一下
    2017-09-09
  • React中useEffect原理的代碼簡單實現(xiàn)詳解

    React中useEffect原理的代碼簡單實現(xiàn)詳解

    React的useEffect鉤子是React函數(shù)組件中處理副作用,本文將通過一個簡單的例子解釋如何用代碼實現(xiàn)useEffect的基本原理,感興趣的小伙伴可以了解下
    2023-12-12
  • 在?React?項目中全量使用?Hooks的方法

    在?React?項目中全量使用?Hooks的方法

    這篇文章主要介紹了在?React?項目中全量使用?Hooks,使用 Hooks 能為開發(fā)提升不少效率,但并不代表就要拋棄 Class Component,依舊還有很多場景我們還得用到它,本文給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2022-10-10
  • React組件生命周期詳解

    React組件生命周期詳解

    本篇文章主要介紹了React組件生命周期,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-07-07
  • React中props驗證不足的問題及解決方案

    React中props驗證不足的問題及解決方案

    在?React?開發(fā)中,props?是組件間通信的重要方式,通過?props,父組件可以向子組件傳遞數(shù)據(jù)和回調(diào)函數(shù),然而,如果對?props?的驗證不足,可能會導(dǎo)致類型錯誤、運行時錯誤或難以調(diào)試的問題,本文將探討?React?中?props?驗證不足的常見問題,并提供解決方案
    2025-03-03
  • React Fiber中面試官最關(guān)心的技術(shù)話題

    React Fiber中面試官最關(guān)心的技術(shù)話題

    這篇文章主要為大家介紹了React Fiber中面試官最關(guān)心的技術(shù)話題解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-06-06
  • React?組件傳?children?的各種案例方案詳解

    React?組件傳?children?的各種案例方案詳解

    自定義組件的時候往往需要傳?children,由于寫法比較多樣,我就總結(jié)了一下,要自定義的組件其中包含一個?title?和一個?children,本文通過實例代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧
    2023-10-10
  • react中使用video.js的踩坑記錄

    react中使用video.js的踩坑記錄

    這篇文章主要介紹了react中使用video.js的踩坑記錄,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-07-07
  • 詳解React+Koa實現(xiàn)服務(wù)端渲染(SSR)

    詳解React+Koa實現(xiàn)服務(wù)端渲染(SSR)

    這篇文章主要介紹了詳解React+Koa實現(xiàn)服務(wù)端渲染(SSR),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-05-05
  • 詳解在React-Native中持久化redux數(shù)據(jù)

    詳解在React-Native中持久化redux數(shù)據(jù)

    這篇文章主要介紹了在React-Native中持久化redux數(shù)據(jù),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-05-05

最新評論

阳城县| 福海县| 利川市| 宁晋县| 韶关市| 吐鲁番市| 巴彦淖尔市| 宿迁市| 三穗县| 原平市| 丰城市| 盘山县| 万年县| 阳西县| 施秉县| 阿巴嘎旗| 江永县| 牟定县| 新和县| 宁蒗| 康保县| 米林县| 马关县| 祥云县| 盐源县| 小金县| 永川市| 望城县| 商河县| 墨玉县| 岳普湖县| 平果县| 仪陇县| 合山市| 塔城市| 芜湖县| 阿巴嘎旗| 云浮市| 昭平县| 金塔县| 广水市|