欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

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

一、前言

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

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

二、用法

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

  • 1.通過Consumer來消費(fèi)上下文
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來消費(fèi)上下文
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來消費(fèi)上下文
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ù)組件中使用

三、缺點(diǎn)

這里有一個(gè)例子:

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

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

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

四、context優(yōu)化

我們知道,所有消費(fèi)了context的地方,只要Providervalue值發(fā)生變化,都會(huì)發(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 })}>
          點(diǎn)擊
        </button>
        <TestUseContextSon2 />
      </globalContext.Provider>
  );
}

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

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

二重奏--使用shouldComponentUpdate

此處由于作者比較任性,省略100字,基本效果其實(shí)和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 })}>
          點(diǎn)擊
        </button>
        <TestUseContextSon3 />
      </globalContext.Provider>
  );
}

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

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

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

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

上面所述的三種方法都存在一個(gè)弊端,Provider的直接下級(jí)組件都需要用memoPureComponent、shouldComponentUpdate處理,才能屏蔽掉父級(jí)狀態(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é)點(diǎn)。

效果如下:

當(dāng)我們點(diǎn)擊按鈕時(shí),打印如下:

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

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

出現(xiàn)這種現(xiàn)象,其實(shí)是props.children引起的,props.children指向一個(gè)對(duì)象,這個(gè)對(duì)象中存放著<Son1 />、<Son2 />、<Son3 />執(zhí)行的結(jié)果,ThemeProvider執(zhí)行的時(shí)候,props.children指向的對(duì)象沒有發(fā)生變化,只有當(dāng)ContextChildren組件重新渲染的時(shí)候,<Son1 /><Son2 />、<Son3 />才會(huì)重新執(zhí)行,由于我們將狀態(tài)放置于ThemeProvider組件中,所以ContextChildren組件不會(huì)重新渲染,<Son1 />、<Son2 />、<Son3 />也就不會(huì)重新執(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í)行了,我想這是因?yàn)榭寺≈笾赶虬l(fā)生變化,導(dǎo)致組件重新執(zhí)行

總結(jié)

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

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

相關(guān)文章

  • 基于React Context實(shí)現(xiàn)一個(gè)簡單的狀態(tài)管理的示例代碼

    基于React Context實(shí)現(xiàn)一個(gè)簡單的狀態(tài)管理的示例代碼

    本文主要介紹了基于React Context實(shí)現(xiàn)一個(gè)簡單的狀態(tài)管理的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07
  • React-Native左右聯(lián)動(dòng)List的示例代碼

    React-Native左右聯(lián)動(dòng)List的示例代碼

    本篇文章主要介紹了React-Native左右聯(lián)動(dòng)List的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-09-09
  • Redux中subscribe的作用及說明

    Redux中subscribe的作用及說明

    由于redux使用這方面有很多的不解,不是很熟練,所以我查找資料,進(jìn)行一個(gè)總結(jié),希望可以鞏固知識(shí),并且能幫助到需要的人,所以我會(huì)寫的比較清晰簡單明了點(diǎn),若有不對(duì)之處,請大家糾正
    2023-10-10
  • react-router-dom v6版本跳轉(zhuǎn)路徑的實(shí)現(xiàn)方法

    react-router-dom v6版本跳轉(zhuǎn)路徑的實(shí)現(xiàn)方法

    這篇文章主要介紹了react-router-dom v6版本跳轉(zhuǎn)路徑的實(shí)現(xiàn)方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • Input標(biāo)簽自動(dòng)校驗(yàn)功能去除實(shí)現(xiàn)

    Input標(biāo)簽自動(dòng)校驗(yàn)功能去除實(shí)現(xiàn)

    這篇文章主要為大家介紹了Input標(biāo)簽的自動(dòng)拼寫檢查功能去除實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-07-07
  • react 項(xiàng)目 中使用 Dllplugin 打包優(yōu)化技巧

    react 項(xiàng)目 中使用 Dllplugin 打包優(yōu)化技巧

    在用 Webpack 打包的時(shí)候,對(duì)于一些不經(jīng)常更新的第三方庫,比如 react,lodash,vue 我們希望能和自己的代碼分離開,這篇文章主要介紹了react 項(xiàng)目 中 使用 Dllplugin 打包優(yōu)化,需要的朋友可以參考下
    2023-01-01
  • react 報(bào)錯(cuò)Module build failed: BrowserslistError: Unknown browser query `dead`問題的解決方法

    react 報(bào)錯(cuò)Module build failed: Browserslis

    這篇文章主要介紹了react 報(bào)錯(cuò)Module build failed: BrowserslistError: Unknown browser query `dead`問題的解決方法,需要的朋友可以參考下
    2023-06-06
  • Webpack3+React16代碼分割的實(shí)現(xiàn)

    Webpack3+React16代碼分割的實(shí)現(xiàn)

    這篇文章主要介紹了Webpack3+React16代碼分割的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • React表中顯示JSON數(shù)據(jù)demo

    React表中顯示JSON數(shù)據(jù)demo

    這篇文章主要為大家介紹了React表中顯示JSON數(shù)據(jù)demo,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • React項(xiàng)目配置axios和反向代理和process.env環(huán)境配置等問題

    React項(xiàng)目配置axios和反向代理和process.env環(huán)境配置等問題

    這篇文章主要介紹了React項(xiàng)目配置axios和反向代理和process.env環(huán)境配置等問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-12-12

最新評(píng)論