位置: IT常识 - 正文

react context优化四重奏教程示例

编辑:rootadmin
这篇文章主要为大家介绍了react context优化四重奏教程示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪 目录

推荐整理分享react context优化四重奏教程示例,希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:,内容如对您有帮助,希望把文章链接给更多的朋友!

一、前言二、用法三、缺点四、context优化一重奏--使用PureComponent二重奏--使用shouldComponentUpdate三重奏--使用React.memo四重奏--Provider再封装+props.children总结一、前言

我们在使用react的过程中,经常会遇到需要跨层级传递数据的情况。props传递数据应用在这种场景下会极度繁琐,且不利于维护,于是context应运而生

官方解释: 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.通过静态变量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既可以在类组件中使用,也可以在函数组件中使用contextType只能在类组件中使用useContext只能在函数组件中使用三、缺点

这里有一个例子:

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

当我们改变value值时,会导致Son1、Son2都发生重渲染,但这与我们的初衷相悖,造成了额外的开销,我们期望做到的是Son1不执行,Son2重新渲染。在较长的一段时间内,我都认为是使用了context导致Provider下面的子组件发生了重渲染。网上也有很多解释没有说清楚,容易误导人。

实际情况是value的变化导致了Son1、Son2发生重渲染。如下示例: 即使我们不使用·context,当value发生变化时,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中传入一个状态,但是当状态改变时又不可避免的造成Provider下的所有子组件重新渲染,我们期望只有消费了上下文的子组件重新渲染,那么有什么方法能够避免这种额外的开销吗?

四、context优化

我们知道,所有消费了context的地方,只要Provider的value值发生变化,都会发生重渲染.只要我们有什么办法能够避开父组件状态发生变化,引起的子组件状态发生变化,那就可以减少很多不必要的开销。

一重奏--使用PureComponentconst 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各执行一遍

点击按钮之后,TestUseContextSon2----render没有打印,Consumer----handle打印,达到预期结果。

二重奏--使用shouldComponentUpdate

此处由于作者比较任性,省略100字,基本效果其实和PureComponent一致,不做过多描述。

三重奏--使用React.memo

React.memo既可以用于函数组件,也可以用于类组件

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

react context优化四重奏教程示例

点击按钮之后,TestUseContextSon2----render没有打印,Consumer----handle打印,达到预期结果。 那如果我们使用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打印,也就是说当我们使用useContext来消费上下文的时候,整个函数组件会重新执行。而Consumer仅仅只是局部执行,这意味更少的性能消耗。

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

上面所述的三种方法都存在一个弊端,Provider的直接下级组件都需要用memo、PureComponent、shouldComponentUpdate处理,才能屏蔽掉父级状态变化带来的影响,那么有没有一种更方便的方式呢?

代码如下:

/** 主题 */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组件,并将状态管理也放在ThemeProvider组件中,然后通过props.children来引入组件子节点。

效果如下:

当我们点击按钮时,打印如下:

点击按钮,setTheme执行,状态由{ theme: "red" }变为{ theme: "blue" },引起ThemeProvider组件重新执行,打印ThemeProvider----- blue,组件Son2由于消费了上下文,重新执行,打印Son2---- blue

那么问题来了,为什么没有打印Son4呢?我们没有使用memo、PureComponent等处理Son4组件,但是它确实不会重新执行。

出现这种现象,其实是props.children引起的,props.children指向一个对象,这个对象中存放着<Son1 />、<Son2 />、<Son3 />执行的结果,ThemeProvider执行的时候,props.children指向的对象没有发生变化,只有当ContextChildren组件重新渲染的时候,<Son1 />、<Son2 />、<Son3 />才会重新执行,由于我们将状态放置于ThemeProvider组件中,所以ContextChildren组件不会重新渲染,<Son1 />、<Son2 />、<Son3 />也就不会重新执行,所以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依然没有执行

再改一下:

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执行了,我想这是因为克隆之后指向发生变化,导致组件重新执行

总结

本文简单介绍了一下context的几种用法,以及如何来屏蔽父级状态变化(provider的value一般是和父级组件状态挂钩的)导致未消费上下文的子组件重新渲染导致的额外开销。

以上就是react context优化四重奏教程示例的详细内容,更多关于react context 优化教程的资料请关注本站其它相关文章!

本文链接地址:https://www.jiuchutong.com/zhishi/310835.html 转载请保留说明!

上一篇:织梦网站如何用jQuery.lazyload延时加载图片(织梦系统网站搭建教程)

下一篇:python中shell如何逐行输入?(python的shell怎么运行文件)

  • 论坛发帖要求才能保证效果和行业进步(论坛发帖有哪些注意事项)

    论坛发帖要求才能保证效果和行业进步(论坛发帖有哪些注意事项)

  • seo博客优化推广的六大方法(seo博客优化推广方案)

    seo博客优化推广的六大方法(seo博客优化推广方案)

  • oppo手机拍照怎么显示时间(oppo手机拍照怎么显示日期时间)

    oppo手机拍照怎么显示时间(oppo手机拍照怎么显示日期时间)

  • 微信如何查看自己的年度账单(微信如何查看自己的群聊)

    微信如何查看自己的年度账单(微信如何查看自己的群聊)

  • 小米10至尊纪念版有红外线功能吗(小米10至尊纪念版换屏幕多少钱)

    小米10至尊纪念版有红外线功能吗(小米10至尊纪念版换屏幕多少钱)

  • 苹果怎么限制地区来电(苹果怎么限制地区下载)

    苹果怎么限制地区来电(苹果怎么限制地区下载)

  • 抖音手机号换了收不到验证码怎么办(抖音手机号换了怎么找回以前的抖音号)

    抖音手机号换了收不到验证码怎么办(抖音手机号换了怎么找回以前的抖音号)

  • b站能知道是谁举报我吗(b站知道是谁发的弹幕吗)

    b站能知道是谁举报我吗(b站知道是谁发的弹幕吗)

  • iphone7p有红外遥控功能吗(iphone7 红外)

    iphone7p有红外遥控功能吗(iphone7 红外)

  • iphone11突然发出巨大嗡嗡声(iphone11突然发出噪音)

    iphone11突然发出巨大嗡嗡声(iphone11突然发出噪音)

  • iphone11快充会有提示吗(苹果11的快充会损坏电池吗)

    iphone11快充会有提示吗(苹果11的快充会损坏电池吗)

  • 换屏后屏幕亮度降低(换屏后屏幕亮度不均匀)

    换屏后屏幕亮度降低(换屏后屏幕亮度不均匀)

  • 国内通用流量怎么使用(国内通用流量怎么用不了)

    国内通用流量怎么使用(国内通用流量怎么用不了)

  • 打语音电话闹钟会响吗(打语音电话闹钟响了中断怎么办)

    打语音电话闹钟会响吗(打语音电话闹钟响了中断怎么办)

  • 电子发票下载后打不开(电子发票下载后找不到)

    电子发票下载后打不开(电子发票下载后找不到)

  • 网易云最近播放在哪(网易云最近播放是实时的吗)

    网易云最近播放在哪(网易云最近播放是实时的吗)

  • 小米8插OTG没反应

    小米8插OTG没反应

  • 收款账号地区码怎么查(中国建设银行收款账号地区码)

    收款账号地区码怎么查(中国建设银行收款账号地区码)

  • word取消两页并排(word如何取消两页并排)

    word取消两页并排(word如何取消两页并排)

  • 云文档怎么用(云文档怎么用电脑打开)

    云文档怎么用(云文档怎么用电脑打开)

  • 建个网站需要什么手续(建网站需要什么软件)

    建个网站需要什么手续(建网站需要什么软件)

  • 货拉拉1000押金退流程(货拉拉1000押金怎么退)

    货拉拉1000押金退流程(货拉拉1000押金怎么退)

  • 苹果11长宽高(苹果14pro尺寸长宽高多少厘米)

    苹果11长宽高(苹果14pro尺寸长宽高多少厘米)

  • 扫一扫怎么改成前置(扫一扫直接变成文字)

    扫一扫怎么改成前置(扫一扫直接变成文字)

  • 如何解决Win10截屏屏幕会缩小?(win10j截图)

    如何解决Win10截屏屏幕会缩小?(win10j截图)

  • 移动硬盘通过Mac磁盘工具抹掉磁盘不小心强制退出急救方法(移动硬盘通过软件改硬盘容量怎么改)

    移动硬盘通过Mac磁盘工具抹掉磁盘不小心强制退出急救方法(移动硬盘通过软件改硬盘容量怎么改)

  • HTML使用Element-UI制作管理系统页面(无需脚手架以及创建vue工程)(element html)

    HTML使用Element-UI制作管理系统页面(无需脚手架以及创建vue工程)(element html)

  • 大学生web前端期末大作业实例代码 (1500套,建议收藏) HTML+CSS+JS(大学生web前端期刊有哪些)

    大学生web前端期末大作业实例代码 (1500套,建议收藏) HTML+CSS+JS(大学生web前端期刊有哪些)

  • 税前扣除的项目包括
  • 税收优惠属于政策吗
  • 应收账款平均余额包括应收票据吗
  • 公司办资质的发票入什么科目
  • 摄影服务属于哪个开票类目
  • 机票行程单能报销几次
  • 查账征收的个体户怎么报税
  • 房地产业营改增
  • 中外合资经营企业法
  • 收回以前年度的应收账款,怎么进行账务处理?
  • 行政事业单位应当进行摊销的无形资产
  • 多付银行承兑退回的会计分录怎么写?
  • 销项负数发票如何勾选
  • 应收账款计提坏账准备是谨慎性原则吗
  • 报销数字证书续费作财务凭证怎么做?
  • 出口退税转为免税
  • 普通发票和增值税发票都能报销吗
  • 个人是否可以开展募捐
  • 土地增值税计税依据
  • 简述资产的概念特征以及确认条件
  • 利息收入是否缴纳印花税
  • 劳务派遣 税务
  • 公司控股的公司下子公司有哪些
  • 坏账准备为负数怎么填资产负债表
  • 出口企业免抵退是什么意思
  • 蓝牙有哪些功能
  • 房产税和土地使用税征税对象
  • 开展党建系列活动
  • 若依框架好用吗
  • win7指定程序用指定网卡
  • synaudsrv.exe是什么
  • 贷款滞纳金如何收取
  • 建筑安装发票可以外地开吗
  • 什么公司可以开专票
  • vue3如何实现使用SortableJs插件进行表格内的数据项拖拽排序
  • 收入凭证填写
  • 企业取得交易性金融资产时
  • 无人驾驶基础知识
  • vue从0创建一个项目
  • python datetime把日期转换字符串
  • 耕地里埋坟国家有什么规定
  • 企业收取的罚款需要交企业所得税吗
  • 收到增值进项发票
  • 未达起征点销售额
  • 其他资本公积主要包括
  • 预算收入支出
  • 含税与不含税的计算公式
  • 结转本月应交增值税
  • 公司收到注册资本金需要做哪些呢
  • 银行对帐单
  • 去年多计提的费用
  • 研发支出怎么结转到管理费用
  • 如何查看员工社保
  • 其他流动资产
  • 建立明细账的操作步骤
  • 工业会计建账做账流程
  • linux如何查询
  • linux虚拟局域网搭建
  • kvm虚拟化网络配置
  • 如何关闭windows防火墙
  • 新手教程进不去
  • WIN7系统如何恢复出厂系统
  • linux shell脚本实例
  • win7连接路由器设置
  • nodejs解析路径
  • ug语法错误
  • python制作windows安装程序
  • jquery 入门
  • android设计模式总结
  • js获取form表单数据并显示
  • python的垃圾处理机制
  • 中国移动怎么下载账单
  • 临沂市国家税务局人员名单
  • 非正常户解除申请理由
  • 代发工资法律依据
  • 关于出口退税的问题
  • 税务局党支部党员大会会议记录
  • 姓名验证不正确
  • 重庆地税局官网公众号
  • 监察室主任岗位职责
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设