React Hooks大全—useContext

在本文中,我们将重点介绍useContext这个Hook,它可以让你在函数组件中轻松地访问React Context,从而实现跨组件的状态共享。我们将从基本使用,实现原理,最佳实践,以及一些常见的问题和解决方案来探讨useContext的用法和优势。我们还将给出一些必要的代码示例,帮助你更好地理解和应用useContext。

基本使用

公众号:Code程序人生,个人网站:https://creatorblog.cn

React Context是一种在组件树中传递数据的机制,它可以让你在任何层级的组件中访问同一个数据,而不需要通过props逐层传递。这对于一些全局的状态,比如主题,语言,用户信息等,非常有用。

要使用React Context,你需要先创建一个Context对象,然后在根组件中使用Context.Provider组件来提供一个Context值,最后在任何子组件中使用Context.Consumer组件来消费这个值。例如:

// 创建一个Context对象
const ThemeContext = React.createContext('light');// 在根组件中使用Provider提供一个Context值
class App extends React.Component {render() {return (<ThemeContext.Provider value="dark"><Toolbar /></ThemeContext.Provider>);}
}// 在子组件中使用Consumer消费Context值
function Toolbar(props) {return (<div><ThemedButton /></div>);
}function ThemedButton() {return (<ThemeContext.Consumer>{value => <Button theme={value} />}</ThemeContext.Consumer>);
}

这种方式虽然可以实现Context的访问,但是有一些缺点:

  • 每次使用Context值,都需要引入一个Consumer组件,这会增加组件树的层级和复杂度。
  • 如果一个组件需要访问多个Context,那么就需要嵌套多个Consumer组件,这会导致代码的可读性和维护性降低。
  • Consumer组件需要使用一个函数作为子元素,这会导致每次渲染都会创建一个新的函数,这会影响性能和内存的使用。

为了解决这些问题,React Hooks提供了一个useContext这个Hook,它可以让你在函数组件中直接访问Context值,而不需要使用Consumer组件。

useContext的用法非常简单,只需要传入一个Context对象,就可以返回这个Context的当前值。例如:

// 创建一个Context对象
const ThemeContext = React.createContext('light');// 在根组件中使用Provider提供一个Context值
function App() {return (<ThemeContext.Provider value="dark"><Toolbar /></ThemeContext.Provider>);
}// 在子组件中使用useContext访问Context值
function Toolbar(props) {return (<div><ThemedButton /></div>);
}function ThemedButton() {// 使用useContext获取Context值const theme = useContext(ThemeContext);return <Button theme={theme} />;
}

可以看到,使用useContext后,代码变得更加简洁,清晰,易读。useContext的优点有:

  • 不需要使用Consumer组件,减少了组件树的层级和复杂度。
  • 可以在一个组件中访问多个Context,只需要多次调用useContext即可,不需要嵌套Consumer组件。
  • 不需要使用函数作为子元素,避免了每次渲染都创建新的函数的问题,提高了性能和内存的使用。

实现原理

要理解useContext的实现原理,我们首先需要了解一下React Context的实现原理。React Context是基于发布订阅模式的,它的核心思想是:

  • 创建一个Context对象,它包含了一个Provider组件和一个Consumer组件,以及一些内部的属性和方法。
  • Provider组件接收一个value属性,它会将这个value保存在Context对象的内部属性中,并且将自己的实例添加到Context对象的订阅者列表中。
  • Consumer组件会从Context对象的内部属性中读取value,并且将自己的实例添加到Context对象的订阅者列表中。
  • 当Provider组件的value属性发生变化时,它会触发Context对象的更新方法,这个方法会遍历订阅者列表,通知所有的订阅者重新渲染,从而获取最新的value。

基于这个原理,我们可以简单地实现一个自定义的Context,代码如下:

// 创建一个自定义的Context对象
function createContext(defaultValue) {// 定义一个Context类,它的实例就是一个Context对象class Context {// 构造函数,接收一个默认值constructor(defaultValue) {// 初始化内部属性this.value = defaultValue; // 保存当前的Context值this.subscribers = []; // 保存订阅者列表}// 定义一个Provider组件,它接收一个value属性Provider = props => {// 将value属性保存在Context对象的内部属性中this.value = props.value;// 将Provider组件的实例添加到订阅者列表中this.subscribers.push(this);// 返回一个普通的div元素,渲染子元素return <div>{props.children}</div>;};// 定义一个Consumer组件,它接收一个函数作为子元素Consumer = props => {// 从Context对象的内部属性中读取valueconst value = this.value;// 将Consumer组件的实例添加到订阅者列表中this.subscribers.push(this);// 返回一个普通的div元素,渲染子元素,传入value作为参数return <div>{props.children(value)}</div>;};// 定义一个更新方法,它会遍历订阅者列表,通知所有的订阅者重新渲染update = () => {for (let subscriber of this.subscribers) {subscriber.forceUpdate();}};}// 返回一个Context对象的实例return new Context(defaultValue);
}

有了这个自定义的Context,我们就可以像使用React Context一样使用它,例如:

// 创建一个自定义的Context对象
const ThemeContext = createContext('light');// 在根组件中使用Provider提供一个Context值
function App() {const [theme, setTheme] = useState('light');return (<ThemeContext.Provider value={theme}><h1>Current theme: {theme}</h1><button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>Toggle theme</button><Toolbar /></ThemeContext.Provider>);
}// 在子组件中使用useContext访问Context值
function Toolbar(props) {return (<div><ThemedButton /></div>);
}function ThemedButton() {// 使用useContext获取Context值const theme = useContext(ThemeContext);return <Button theme={theme} />;
}

可以看到,这个自定义的useContext也可以正常地工作,当我们点击切换主题的按钮时,ThemedButton组件会根据Context值的变化而重新渲染。

最佳实践

使用useContext可以让你在函数组件中轻松地访问Context值,但是也有一些注意事项和最佳实践,我们在这里总结一下:

  • 尽量避免在Context中存储过多的数据,因为每次Context值变化,所有的订阅者都会重新渲染,这会影响性能。如果你需要存储一些复杂的状态,可以考虑使用useReducer或者Redux等状态管理库。
  • 尽量避免在Context中存储一些不稳定的数据,比如函数,对象,数组等,因为每次渲染都会创建新的引用,这会导致Context值的不必要的变化,从而触发订阅者的重新渲染。如果你需要在Context中传递一些函数,可以考虑使用useCallback来缓存函数的引用,避免每次渲染都创建新的函数。
  • 尽量避免在Context中存储一些不相关的数据,比如主题,语言,用户信息等,因为这些数据的变化可能是独立的,但是如果放在同一个Context中,就会导致所有的订阅者都重新渲染,即使他们只关心其中的一部分数据。如果你需要在Context中传递一些不相关的数据,可以考虑使用多个Context,每个Context只负责一种数据,这样可以减少不必要的渲染。

总结

useContextReact Hooks提供的一个强大的Hook,它可以让你在函数组件中直接访问Context值,而不需要使用Consumer组件。useContext的用法非常简单,只需要传入一个Context对象,就可以返回这个Context的当前值。useContext的优点有:

  • 不需要使用Consumer组件,减少了组件树的层级和复杂度。
  • 可以在一个组件中访问多个Context,只需要多次调用useContext即可,不需要嵌套Consumer组件。
  • 不需要使用函数作为子元素,避免了每次渲染都创建新的函数的问题,提高了性能和内存的使用。

useContext的实现原理也非常简单,它只需要做两件事:

  • 从Context对象的内部属性中读取value,并返回给函数组件。
  • 在函数组件的渲染过程中,将函数组件的实例添加到Context对象的订阅者列表中,以便在Context值变化时,能够触发函数组件的重新渲染。

使用useContext时,也有一些注意事项和最佳实践,我们总结了一下:

  • 尽量避免在Context中存储过多的数据,因为每次Context值变化,所有的订阅者都会重新渲染,这会影响性能。
  • 尽量避免在Context中存储一些不稳定的数据,比如函数,对象,数组等,因为每次渲染都会创建新的引用,这会导致Context值的不必要的变化,从而触发订阅者的重新渲染。
  • 尽量避免在Context中存储一些不相关的数据,比如主题,语言,用户信息等,因为这些数据的变化可能是独立的,但是如果放在同一个Context中,就会导致所有的订阅者都重新渲染,即使他们只关心其中的一部分数据。

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

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

相关文章

域名群站开源系统分享开源域名授权系统

一、需要自己安装PHP和MYSQL服务器环境。 二、务必设置伪静态规则&#xff0c;否则将无法访问文章栏目页面。 三、启用伪静态功能&#xff0c;请在站点设置中选择使用thinkphp的伪静态规则。 四、在域名的根目录下找到”data/config.php”文件&#xff0c;填入数据库的账号和…

C++ 中 static 应用

static 实验介绍 在 C/C++ 中都可以使用 static 关键字,但是却需要注意在 C 与 C++ 的使用方法有差异。C++ 除了继承 C 中 static 的使用方法外还增加了新的使用方法。本次实验主要介绍 static 在 C++ 中的使用方法。 静态的成员在实例化对象之前已经产生,并将数据存放在全…

配置zabbix监控平台

目录 内容纯手敲&#xff0c;难免有误&#xff0c;若发现请私信我。 配置zabbix监控平台 一、进入官网 ​编辑​ 二、配置zabbix-server&#xff08;服务端&#xff09; 1.下载zabbix的yum源 2.安装Zabbix服务器、前端、代理 3.安装Zabbix前端 4.编辑文件/etc/yum.rep…

openssl3.2 - quic服务的运行

文章目录 openssl3.2 - quic服务的运行概述笔记运行openssl编译好的quic服务程序todo - 如果自己编译quic服务工程补充 - 超过30秒不连接uqic服务会退出END openssl3.2 - quic服务的运行 概述 在看 官方 guide目录下的工程. 都是客户端程序, 其中有quic客户端, 需要运行quic服…

【算法Hot100系列】旋转图像

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学习,不断总结,共同进步,活到老学到老导航 檀越剑指大厂系列:全面总结 jav…

开发安全之:Cross-Site Scripting (XSS) 漏洞

近期&#xff0c;我会结合研发云陆续发布开发安全相关的文章&#xff0c;欢迎大家关注&#xff01; Overview echo json_encode($arr)&#xff1a;向一个 Web 浏览器发送了未验证的数据&#xff0c;从而导致该浏览器执行恶意代码。 Details Cross-Site Scripting (XSS) 漏洞…

软件测试|python如何去除文件后缀名?

简介 在Python中&#xff0c;我们常常需要操作文件&#xff0c;包括文件的读取、写入、重命名等操作。在文件操作中&#xff0c;我们经常会遇到需要去除文件后缀的问题。那么&#xff0c;Python如何去除文件后缀呢&#xff1f;本文我们将介绍如何使用Python来去除文件后缀。 …

大模型学习与实践笔记(六)

一、finetune 简介 两种微调模式&#xff1a;增量预训练 与指令跟随 1.增量预训练 2.指令微调 二、LoRA 与 QLoRA 介绍 三、XTuner 介绍 四、低显存玩转LLM的方法

Spring Boot整理-Spring Boot的优势

Spring Boot 提供了多个显著的优势,特别是对于快速开发和简化 Spring 应用的配置和部署。这些优势包括: 简化配置:Spring Boot 的“约定优于配置”的原则意味着许多 Spring 应用的常见配置项被自动设置,这减少了开发人员需要编写和维护的配置代码量。快速启动和部署:Sprin…

陶哲轩工作流之人工智能数学验证+定理发明工具LEAN4 [线性代数篇2前置知识]不同求和范围不同函数项结果相等的条件

有空点赞我的视频哦&#xff1a;陶哲轩工作流之人工智能数学验证定理发明工具LEAN4 [线性代数篇2前置知识]不同求和范围不同函数项结果相等的条件_哔哩哔哩_bilibili -- 反向推理 refine sum_bij _ _ _ _ _ -- {s : Finset α} {t : Finset γ} {f : α → β} {g : γ → β…

Linux网络之PXE高效批量装机、Kickstart全自动化安装

一. PXE网络装机简介和相关知识 1. 常见的三种系统安装方式和相关文件 ① 三种系统安装方式 u启动安装&#xff1a;在U盘中下载相关的安装系统及镜像文件&#xff0c;u盘插机安装 光驱安装&#xff1a;将带有所需系统的光盘放进电脑服务器中&#xff0c;按照官方引导装机 …

春节假期出游一些很实用的手机技巧!这样玩,就很哇塞~

随着春节的脚步越来越近&#xff0c;无论是准备出游还是回家&#xff0c;你蠢蠢欲动的心是否已经拦不住了&#xff1f;华为 nova 12系列这些很哇塞的玩法你必须知道&#xff01;这个新年让你旅行出圈有秘籍&#xff01; 出发前智慧播报航班信息不错过。智慧播报的功能就很实…

AI大模型学习笔记之二:什么是 AI 大模型的训练和推理?

在人工智能&#xff08;AI&#xff09;的领域中&#xff0c;我们经常听到训练&#xff08;Training) 和 推理&#xff08;Inference) 这两个词汇&#xff0c;它们是构建强大 AI 模型的关键步骤。我们通过类比人类的学习过程来理解这两个概念&#xff0c;可以更加自然而生动地理…

JUC(java.util.concurrent)的常见类(多线程编程常用类)

Callable接口 这个东西可以类比于之前见过的Runnable接口.两者的区别在于Runnable关注执行过程,不关注执行结果.Callable关注执行结果,它之中的call方法(类比于run方法)返回值就是线程执行任务的结果.Callable<V>里面的V期望线程的入口方法里,返回值是啥类型,此处的泛型参…

Servlet中访问网页常遇到的问题

网页出现404 出现这一种情况是浏览器访问的资源不存在 第一种情况通常是路径出错请检查你的路径是否一致 第二种情况确认你的webapp是否被正确加载 smart tomcat由于只加载一个webapp 如果加载失败 就会直接启动失败 拷贝war方式到Tomcat要加载多个webapp如果失败只有日志 查…

软件测试|sqlalchemy relationship

简介 SQLAlchemy是一个流行的Python ORM&#xff08;对象关系映射&#xff09;库&#xff0c;它允许我们以面向对象的方式管理数据库。在SQLAlchemy中&#xff0c;relationship是一个重要的功能&#xff0c;用于建立表之间的关系。在本文中&#xff0c;我们将详细探讨relation…

AutoRuns下载安装使用教程(图文教程)超详细

「作者简介」&#xff1a;CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」&#xff1a;对网络安全感兴趣的小伙伴可以关注专栏《网络安全入门到精通》 AutoRuns 是微软提供的一款「启动项管理」工具&#xff0c;可以检查开机自动加载的所有程…

UI设计中插画赏析和产品色彩分析

插画赏析&#xff1a; 1. 插画是设计的原创性和艺术性的基础 无论是印刷品、品牌设计还是UI界面&#xff0c;更加风格化的插画能够将不同的风格和创意加入其中&#xff0c;在激烈的竞争中更容易因此脱颖而出。留下用户才有转化。 2. 插画是视觉触发器&#xff0c;瞬间传达大量…

Effective C++——尽可能使用const

const允许指定一个语义约束&#xff08;也就是指定一个“不该被改动”的对象&#xff09;&#xff0c;而编译器会强制实施这项约束。只要保持某个值不变是事实&#xff0c;就应该说出来。以获得编译器的协助&#xff0c;保证不被违反。 const与指针 注意const的写法&#xff0…

国产阿里的Copilot能提效30%吗?

国产阿里的Copilot能提效30%吗&#xff1f; Copilot简介 GitHub 和 OpenAI 共同打造的一款编程神器–Copilot&#xff0c; 这是一款立足于人工智能技术的编程助手。在此基础上&#xff0c;借助于 GitHub 庞大的代码库和来自全球的开源社区帮助&#xff0c;搭配 OpenAI 在自然…