React Context

news2024/10/7 14:33:08

Context

https://juejin.cn/post/7244838033454727227?searchId=202404012120436CD549D66BBD6C542177

context 提供了一个无需为每层组件手动添加 props, 就能在组件树间进行数据传递的方法

React 中数据通过 props 属性自上而下(由父及子)进行传递,但此种用法对于某些类型的属性而言极其繁琐(UI 主题,地区偏好),这些属性时应用程序中许多组件都需要的。Context 提供了一种在组件之间共享此类值的方式,而不必显示的通过组件树逐层传递 props

在这里插入图片描述

  1. 创建 context

  2. 使用 context 的 Provider 进行包裹

  3. 使用 contextType 进行接收,this.context 读取

const ThemeContext = React.createContext('light');
   class App extends React.Component {
    render() {
    return (
      <ThemeContext.Provider value="dark">
        <Toolbar />
      </hemeContext.Provider>
    )
    }
   }

function Toolbar() {
  return (
    <div><ThemeButton /></div>
  )
}

class ThemeButton extends React.Component {
// static contextType = ThemeContext
  return <Button theme={this.context} />
}
ThemedButton.contectType = ThemeContext
function ThemedButton() {
  return (
    <ThemeContext.Consumer>
      {(value) => <button>{value}</button>}
    </ThemeContext.Consumer>
  );
}

context 用于不同层级的组件需要访问同样的数据。使得组件的复用性变差

如果只是想避免层层传递的一些属性,可以使用component composition

  • 将组件本身作为 props 传递下去
  • 这种对组件的控制减少了应用中需要传递的 props 数量,在很多场景下会使得代码更加干净,但是并不适用于每一个场景,这种将逻辑提升到组件树的更高层次会使得高层组件变得更加复杂,并且会强行将底层组件适应这样的样式

API

React.createContext

const MyContext = React.createContext(defaultValue);

创建一个 Context 对象,当 React 渲染一个订阅了这个 Context 对象的组件,这个组件会从组件树中离自身最近的那个匹配的 Provider 中读取到当前的 context 值

只有当组件所处的树中没有匹配到 Provider 时,其 defaultValue 参数才会生效。此默认值有助于在不使用 Provider 包装组件的情况下对组件进行测试。将 undefined 传递给 Provider 的 value 时,消费组件的 defaultValue 不会生效。

Context.Provider

<MyContext.Provider value="" />

每个 Context 对象都会返回一个 Provider React 组件,它允许消费组件订阅 context 的变化

Provider 接收一个 value 属性,传递给消费组件。一个 Provider 可以和多个消费组件有对应关系。多个 Provider 可以嵌套使用,里层的会覆盖外层的数据

当 Provider 的 value 值发生变化时,它内部的所有消费组件都会重新渲染。从 Provider 到其内部 consumer 组件(contextType, useContext)的传播不受制于 shouldComponentUpdate 函数,因此当 consumer 组件在其组件跳过更新的情况下也能更新。

生产消费者模型

组件只要定义了 contextType, 就是消费者,消费者可以订阅生产者,消费者可以随时响应状态的变化

context 可以无视中间组件的渲染,依然可以响应生产者数据的变化

通过新旧值检测来确定变化,使用了和 Object.is 相同的算法

=0 === +0 // true
Object.is(-0, +0) // false
注意点
  • context 会根据引用标识来决定何时进行渲染(本质是 value 属性值的比较)
  • 当 provider 的父组件进行重渲染时,可能会在 consumers 组件中触发意外的渲染
  • 当每一次 Provider 重渲染时,由于 value 属性总是被赋值为新的对象,以下的代码会重新渲染所有的 consumer 组件
class App extends React.Component {
  render() {
    return (
      <MyContext.Provider value={{ something: "something" }}>
        <Toolbar />
      </MyContext.Provider>
    );
  }
}
  • 为了防止这种情况,将 value 状态提升到父节点的 state 里
class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: { something: "something" },
    };
  }
  render() {
    return (
      <MyContext.Provider value={{ something: "something" }}>
        <Toolbar />
      </MyContext.Provider>
    );
  }
}
原理
  1. 将初始值存储在 context._currentValue
  2. 创建 Context.Provider 和 Context.Consumer 对应的 ReactElement 对象

在 fiber 树渲染时,通过不同的 workInProgress.tag 处理 Context.Provider 和 Context.Consumer 类型的节点。

在 React 中提供了 3 种消费 Context 的方式

  1. 直接使用 Context.Consumer 组件(也就是上面 createContext 时创建的 Consumer)
  2. 类组件中,可以通过静态属性 contextType 消费 Context
  3. 函数组件中,可以通过 useContext 消费 Context

这三种方式内部都会调用 prepareToReadContext 和 readContext 处理 Context。prepareToReadContext 中主要是重置全局变量为 readContext 做准备。

readContext 的核心逻辑:

  1. 构建 contextItem 并添加到 workInProgress.dependencies 链表(contextItem 中保存了对当前 context 的引用,这样在后续更新时,就可以判断当前 fiber 是否依赖了 context ,从而判断是否需要 re-render)
  2. 返回对应 context 的 _currentValue 值

更新 Context

当触发 Context.Provider 的 re-render 时,重新走 updateContextProvider 中更新的逻辑

核心逻辑:

  1. 从 ContextProvider 的节点出发,向下查找所有 fiber.dependencies 依赖当前 Context 的节点
  2. 找到消费节点时,从当前节点出发,向上回溯标记父节点 fiber.childLanes,标识其子节点需要更新,从而保证了所有消费 3. 了该 Context 的子节点都会被重新渲染,实现了 Context 的更新
总结

在消费阶段,消费者通过 readContext 获取最新状态,并通过 fiber 关联当前 Context
在更新阶段,从 ContextProvider 节点出发查找所有消费了该 context 的节点

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1639871.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Git使用指北

目录 创建一个Git仓库本地仓库添加文件文件提交到本地仓库缓冲区添加远程仓库地址本地仓库推送到远程仓库创建新的分支拉取代码同步删除缓冲区的文件&#xff0c;远程仓库的文件.gitignore文件 创建一个Git仓库 Git仓库分为远程和本地两种&#xff0c;远程仓库如Githu上创建的…

每天五分钟深度学习框架pytorch:如何创建多维Tensor张量元素?

本文重点 上节课程我们学习了如何创建Tensor标量,我们使用torch.tensor。本节课程我们学习如何创建Tensor向量,我们即可以使用torch.Tensor又可以使用torch.tensor,下面我们看一下二者的共同点和不同点。 Tensor张量 tensor张量是一个多维数组,零维就是一个点(就是上一…

Java零基础入门到精通_Day 9

1.ArrayList 编程的时候如果要存储多个数据&#xff0c;使用长度固定的数组存储格式&#xff0c;不一定满足我们的需求&#xff0c;更适应不了变化的需求&#xff0c;那么&#xff0c;此时该如何选择呢? 集 合 集合类的特点:提供一种存储空间可变的存储模型&#xff0c;存储的…

EMP.DLL是什么东西?游戏提示EMP.DLL文件缺失怎么解决

emp.dll文件是Windows操作系统中的一种动态链接库文件&#xff0c;它被设计为可以被多个程序共享使用的模块化文件。这种设计旨在提高系统效率&#xff0c;减少内存消耗&#xff0c;并简化软件的维护和更新。DLL文件通常包含了一系列相关的函数和变量&#xff0c;这些函数和变量…

C++入门系列-内联函数

&#x1f308;个人主页&#xff1a;羽晨同学 &#x1f4ab;个人格言:“成为自己未来的主人~” 以inline修饰的函数叫做内联函数&#xff0c;编译时C编译器会在调用内敛函数的地方展开&#xff0c;这就意味着使用内联函数可以提升程序的运行的效率&#xff0c;减小了调用所需…

微软开源 MS-DOS「GitHub 热点速览」

上周又是被「大模型」霸榜的一周&#xff0c;各种 AI、LLM、ChatGPT、Sora、RAG 的开源项目在 GitHub 上“争相斗艳”。这不 Meta 刚开源 Llama 3 没几天&#xff0c;苹果紧跟着就开源了手机端大模型&#xff1a;CoreNet。 GitHub 地址&#xff1a;github.com/apple/corenet 开…

如何判断自己是不是表演型人格障碍?

表演型人格障碍&#xff0c;也叫寻求注意&#xff0c;寻求关注型人格&#xff0c;癔症型人格&#xff0c;是比较常见的人格障碍类型之一。其核心特征包括有&#xff1a;过分的情绪化&#xff0c;夸张的表现形式&#xff0c;渴望成为别人的关注点&#xff0c;其行为往往是幼稚的…

HDR和WDR有什么区别

HDR指高动态范围成像&#xff0c;与之相对的还有一个概念WDR&#xff08;wide dynamic range&#xff09;宽动态范围成像&#xff0c;从概念上来说二者并无本质区别&#xff0c;为了提高图像的动态范围&#xff0c;解决光照条件不一致时图像过暗或过亮的问题。但它们的原理和应…

QT5带UI的常用控件

目录 新建工程&#xff0c;Qmainwindow带UI UI设计器 常用控件区 Buttons 按钮 containers 容器 控件属性区域 对象监视区 布局工具区 信号与槽区 简单例子1 放置一个按钮控件&#xff0c;改文本为发送&#xff0c;该按键为Button1&#xff1b; 按钮关联信号和…

DRF版本组件源码分析

DRF版本组件源码分析 在restful规范中要去&#xff0c;后端的API中需要体现版本。 3.6.1 GET参数传递版本 from rest_framework.versioning import QueryParameterVersioning单视图应用 多视图应用 # settings.pyREST_FRAMEWORK {"VERSION_PARAM": "versi…

C 深入指针(1)

目录 一、const 1、const修饰变量 2、const修饰指针 2.1 const int* p&#xff08;int const* p&#xff09; 2.2 int* const p 2.3 结论 二、指针运算 1、指针 - 整数 2、指针 - 指针 3、指针的关系运算 三、指针的使用 1、模拟实现 strlen 2、传值调用和传址调用…

读天才与算法:人脑与AI的数学思维笔记16_音乐图灵测试

1. 艾米 1.1. 人工智能作曲家 1.1.1. 分析机可能会生成任意复杂程度、精细程度的科学的音乐作品 1.1.1.1. 阿达洛夫莱斯 1.1.2. 巴赫的作品是大多数作曲家开始学习创作的起点&#xff0c;也是大多数计算机开始学习作曲的起点…

汽车车灯罩通常使用的主要材料包括什么?汽车车灯的灯罩如果破损破裂破洞了要怎么修复?

1.聚碳酸酯&#xff08;PC&#xff09;&#xff1a;PC具有高强度、高韧性和耐冲击性&#xff0c;因此常用于汽车车灯的外罩和透镜部分。它还具有良好的透光性&#xff0c;使得车灯能够有效地发光。 2.丙烯酸酯&#xff08;PMMA&#xff09;&#xff1a;PMMA&#xff0c;也称为…

基于GWO灰狼优化的CNN-LSTM-Attention的时间序列回归预测matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1卷积神经网络&#xff08;CNN&#xff09;在时间序列中的应用 4.2 长短时记忆网络&#xff08;LSTM&#xff09;处理序列依赖关系 4.3 注意力机制&#xff08;Attention&#xff09; 4…

SpringBoot实现图片上传(个人头像的修改)

SpringBootlayui实现个人信息头像的更改 该文章适合对SpringBoot&#xff0c;Thymeleaf&#xff0c;layui入门的小伙伴 废话不多说&#xff0c;直接上干货 Springbootlayui实现头像更换 前端公共部分代码 HTML页面代码 <div class"layui-card-header" style&quo…

[实例] Unity Shader 利用顶点着色器模拟简单水波

我们都知道顶点着色器可以用来改变模型各个顶点的位置&#xff0c;那么本篇我们就利用顶点着色器来做一个模拟简单水波的应用。 1. 简谐运动 在进行模拟水波之前&#xff0c;我们需要了解简谐运动&#xff08;Simple Harmonic Motion&#xff09;公式&#xff1a; 其中&#…

有公网IP的好处?

1. 维护远程连接需求的解决方案 公网IP是指可以通过互联网直接访问的IP地址&#xff0c;相对于私有IP地址而言具有重要的好处。公网IP的最大好处之一是解决了各行业客户的远程连接需求。由于天联组网操作简单、跨平台应用、无网络要求以及独创的安全加速方案等原因&#xff0c…

Python 全栈体系【四阶】(三十八)

第五章 深度学习 八、目标检测 3. 目标检测模型 3.2 YOLO 系列 3.2.1 YOLOv1&#xff08;2016&#xff09; 3.2.1.1 基本思想 YOLO&#xff08;You Only Look Once &#xff09;是继 RCNN&#xff0c;fast-RCNN 和 faster-RCNN 之后&#xff0c;Ross Girshick 针对 DL 目…

人工智能论文:BERT和GPT, GPT-2, GPT-3 的简明对比和主要区别

在BERT的论文里面&#xff1a; 2018.10 BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding&#xff0c;BERT已经解释了BERT&#xff0c;GPT&#xff0c;ELMo的区别。 *ELMo为双向RNN&#xff0c;请忽略。 主要区别&#xff1a; BERT使用的是…

Qt QLCDNumber详解

1.简介 它提供了一个显示数字的显示屏控件&#xff0c;效果类似于现实世界中的液晶显示屏。它可以显示任何大小的数字。它可以显示十进制、十六进制、八进制或二进制数字。可以用setMode更改基数&#xff0c;用setSmallDecimalPoint更改小数点。 2.常用方法 以下是一些常用的…