React Context

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.mfbz.cn/a/588946.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

三数之和细节

这道题看着简单&#xff0c;但是有细节要注意&#xff0c;不能有重复的三元组&#xff0c;我们也不能一开始的时候把重复的元素去除&#xff0c;如果全都是0的话&#xff0c;那么就删除的只剩下一个0了&#xff0c;显然答案是[0,0,0] class Solution { public:vector<vecto…

Jetpack Compose简介

文章目录 Jetpack Compose简介概述声明式UI和命令式UIJetpack Compose和Android View对比Compose API设计原则一切皆为函数组合优于继承单一数据源 Jetpack Compose和Android View关系使用ComposesetContent()源码ComposablePreview Jetpack Compose简介 概述 Jetpack Compos…

用龙梦迷你电脑福珑2.0做web服务器

用龙梦迷你电脑福珑2.0上做web服务器是可行的。已将一个网站源码放到该电脑&#xff0c;在局域网里可以访问网站网页。另外通过在同一局域网内的一台windows10电脑上安装花生壳软件&#xff0c;也可以在外网访问该内网服务器网站网页。该电脑的操作系统属于LAMP。在该电脑上安装…

【python】python标准化考试系统[单项选择题 简易版](源码)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

docker挂载数据卷-以nginx为例

目录 一、什么是数据卷 二、数据卷的作用 三、如何挂载数据卷 1、创建nginx容器挂载数据卷 2、查看数据卷 3、查看数据卷详情 4、尝试在宿主机修改数据卷 5、查看容器内对应的数据卷目录 6、 访问nginx查看效果 ​​​​​​​一、什么是数据卷 挂载数据卷本质上就是实…

基于springboot实现公司日常考勤系统项目【项目源码+论文说明】

基于springboot实现公司日常考勤系统演示 摘要 目前社会当中主要特征就是对于信息的传播比较快和信息内容的安全问题&#xff0c;原本进行办公的类型都耗费了很多的资源、传播的速度也是相对较慢、准确性不高等许多的不足。这个系统就是运用计算机软件来完成对于企业当中出勤率…

Unity3D初级实战项目之方块跑酷

目录 初始化项目开发环境初始化项目屏幕自适应 游戏UI界面元素布局开始界面UI角色选择&#xff08;商城&#xff09;界面UI游戏界面UI 地图生成算法之菱形布局Resources资源加载代码生成地图菱形布局 地图生成算法之墙壁边界菱形地图双排布局地图瓷砖颜色美化墙壁边界生成 地图…

git提交错了?别慌,直接删除提交记录

为什么要删除提交历史 前几天产品提了个很扯淡的需求&#xff0c;我在代码了进行了吐槽.... 要命的是我不下心进行了代码提交&#xff1a; 我们的远程仓库大家都能看见的 这要是被其他人发现就惨了&#xff01;当务之急&#xff0c;我必须立刻马上删除这一条提交记录&#xff…

菜鸡学习netty源码(一)——ServerBootStrap启动

1.概述 对于初学者而然,写一个netty本地进行测试的Server端和Client端,我们最先接触到的类就是ServerBootstrap和Bootstrap。这两个类都有一个公共的父类就是AbstractBootstrap. 那既然 ServerBootstrap和Bootstrap都有一个公共的分类,那就证明它们两个肯定有很多公共的职…

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

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

全景剖析阿里云容器网络数据链路(七):Terway DataPath V2(Terway≥1.8.0)

作者&#xff1a;余凯 前言 近几年&#xff0c;企业基础设施云原生化的趋势越来越强烈&#xff0c;从最开始的IaaS化到现在的微服务化&#xff0c;客户的颗粒度精细化和可观测性的需求更加强烈。容器网络为了满足客户更高性能和更高的密度&#xff0c;也一直在高速的发展和演…

qt学习篇---界面按键关联(信号和槽)

目录 1.qt基础 2.做一个界面 创建project UI界面设计 信号和槽 1.控件改名字 2.什么是信号和槽 3.怎么关联信号和槽 自动关联 手动关联 1.qt基础 qt可移植性强&#xff0c;不久会用到MCU。很有意义学习 2.做一个界面 创建project 不要中文路径 选择QWidget .pro文件…

ASP.NET实验室预约系统的设计

摘 要 实验室预约系统的设计主要是基于B/S模型&#xff0c;在Windows系统下&#xff0c;运用ASP.NET平台和SQLServer2000数据库实现实验室预约功能。该设计主要实现了实验室的预约和管理功能。预约功能包括老师对实验室信息、实验项目和实验预约情况的查询以及对实验室的预约…

LeetCode 69—— x 的平方根

阅读目录 1. 题目2. 解题思路一3. 代码实现一4. 解题思路二5. 代码实现二 1. 题目 2. 解题思路一 二分查找法&#xff0c;对于整数 i ∈ [ 0 , x ] i \in [0,x] i∈[0,x]&#xff0c;我们判断 i 2 i^2 i2 和 x x x 的关系&#xff0c;然后找到最后一个平方小于等于 x x x …

向量语义学

书籍&#xff1a;Vector Semantics 作者&#xff1a;Andrs Kornai 出版&#xff1a;Springer Singapore 书籍下载-《向量语义学》本书通过提出一个以线性多面体术语表达的形式理论来弥合这一差距&#xff0c;该理论将字向量和概念结构进行了概括&#xff0c;将每个词典定义视…

45. UE5 RPG 使用元属性(Meta Attributes)以及使用Set by Caller修改伤害

在RPG游戏中&#xff0c;我们是不会直接修改生命值的属性&#xff0c;是因为在修改角色属性时&#xff0c;需要获取角色的属性并进行复杂的计算&#xff0c;所以&#xff0c;我们正常情况下使用元属性&#xff08;Meta Attributes&#xff09;作为计算的中间的媒。在服务器上先…

前端-React项目初始化

大家好我是苏麟 , 今天聊聊前端依赖 Ant Desgin Pro 快速初始化项目 . Ant Desgin Pro 官网 : 开始使用 - Ant Design Pro 初始化项目 找到文档->快速上手 脚手架命令 : # 使用 npm npm i ant-design/pro-cli -g创建项目命令 : pro create 项目名称 选择简单还是全量 : …

Python | Leetcode Python题解之第64题最小路径和

题目&#xff1a; 题解&#xff1a; class Solution:def minPathSum(self, grid: List[List[int]]) -> int:if not grid or not grid[0]:return 0rows, columns len(grid), len(grid[0])dp [[0] * columns for _ in range(rows)]dp[0][0] grid[0][0]for i in range(1, r…

五大开放式耳机推荐,选对耳机让运动更带感!

看似精彩的户外运动经历背后&#xff0c;其实是枯燥的体能运动和训练&#xff0c;以及独自长途和长时间旅行伴随的孤独感&#xff0c;而排解这些不良情绪的最佳方式就是音乐。如果你希望在运动、舒适、安全和音质之间获得一个最佳平衡&#xff0c;那相比入耳式耳机&#xff0c;…

71.网络游戏逆向分析与漏洞攻防-角色与怪物信息的更新-分析并利用角色与怪物创建的数据包

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 如果看不懂、不知道现在做的什么&#xff0c;那就跟着做完看效果 现在的代码都是依据数据包来写的&#xff0c;如果看不懂代码&#xff0c;就说明没看懂数据包…
最新文章