课程:React18 系统精讲
章节:hooks
讲师:阿莱克斯刘
课程内容:
今天,我学习了react的上下文对象,Context。先提个问题,在react项目中,我们如何传递变量?
打开 index.tsx 文件, 如果我们有个变量叫 username = “阿莱克斯“
。一般来说,我们会通过使用props属性来传递变量,所以这时候我们可以给app组件创建一个username 的属性,然后把变量username传递给这个username prop。
打开app组件,给组件的Props interface 补充username的类型
interface Props { username: string}
然后在组件声明中补充范型,const App: React.FC<Props> = (props) => {
, 。现在,我们就可以从这个参数props中获得从父组件传递来的username的数据了。如果想使用username,很简单,直接调用props.username就可以了。比如我们在网站header下面加上一个h2元素来展示username数据,<h2>{props.username}</h2>
好,打开命令行,npm start 启动网站看看结果是否正确。浏览器正确输出了我们从index传递给app组件的数据:阿莱克斯
我相信任何一个写过react代码的程序员都一定对这种props传递的机制非常非常了解。但是,如果我们想把“阿莱克斯”这个值传递给app的子组件,应该怎么做呢?
回到app组件中,在div里我加一个新的组件,叫<child />
。这是时候,这个child组件想使用username,而不是app自己,那么我们就需要把username再向下传递一级。
<child username={props.username} />
这个机制将会以组件树的形式,将props自上而下传递给所有对username有需求的组件。于是就形成了props的深度注入,英文叫prop's drilling
。通过这个例子,我们不难发现随着props注入越深,组件更新的频率也会愈来越高,而ui效率则会越来越慢,调试起来也会越来越困难。
于是我们就需要有别的方式来解决跨组件数据注入的问题,其中一个解决方案就是使用React的上下文context。React context允许我们的组件直接共享某个数据,而不是通过props注入的方式,这样就能避免出现props drilling。
请看具体实现:
首先,我们还原对app组件的修改,删除h2,删除interface中username的定义
回到index文件,删除app组件的username prpos
为了能够使用react context,我们首先得创建一个context
const appConext = react.createContext()
不过,在创建上下文context的同时,react要求我们必须得先给定一个默认初始值。这个默认初始值是一个对象,可以叫做defaultContextValue 的对象,包含 username: “阿莱克斯”
const defaultContextValue = { username: "阿莱克斯" }
接下来,为了能给app组件以及app的子组件提供数据支持,我们还需要设置一个provider来把整个render函数包裹起来。而provider的名字就是appConext .provide
<appContext.Provider> <App /> </appContext.Provider>
然后我们再把defaultContextValue注入provider的value props里面
<appContext.Provider value={defaultContextValue}>
接下来,我们跳过app组件,进入它的子组件机器人画册Robot,那么在这个嵌套组件中我们如何获取username的数据呢?
import { appContext } from "../index";
<appContext.Consumer> {(value) => ( <div className={styles.cardContainer}> <img alt="robot" src={`https://robohash.org/${id}`} /> <h2>{name}</h2> <p>{email}</p> <p>作者:{value.username}</p> </div> )} </appContext.Consumer>
在渲染逻辑中加入数据的消费方式,使用consumer组件,组件内部使用花括号,只能在箭头函数内部使用共享数据。把之前的jsx渲染逻辑复制粘贴到Consumer内,我们给这个机器人画册组件的最后加一行代码,使用p tag,作者引用context中的内容,{value.username}
react有个特殊的词定义这个数据获取过程,叫做消费,英语consumer
为了消费这个数据,首先需要Export 这个appContext
然后回到Robot组件中引用appContext
好了,代码结束,保存一下文件,打开浏览器,刷新一下页面,正常输出了页面数据,不过,我们仔细观察一下机器人画册组件,我们会发现每张画册下面都加入一行新的作者数据,作者:阿莱克斯。而这个作者的数据就是通过react的上下文关系context传递的。
在react框架中通过provider和consumer来传递数据是一个非常受欢迎模式。但是随着react hooks的引入,于是我们也有了更加简单的方式在组件中消费数据,就是使用“useContex”钩子函数。请同学们打开robot.tsx
在文件开头我们import一下 useContext
import React, {useContext} from "react";
然后在robot组件的开头创建一下Consumer
const value = useContext(appContext)
接下来,我们就能在return 中直接使用value了。请同学们去掉appContext.Consumer,相关的嵌套代码,去掉最外层的花括号,去掉value参数以及箭头函数,其他代码保持不变。
好了,保存一下代码,重新编译网站,现在我们打开浏览器观察
一切正常,数据输出没问题,而且每个机器人画册中依然保留着作者信息,作者:“阿莱克斯”
所以,就是这么简单,新加入的useContex hook 极大的减少了模版代码,降低了代码层级,也消灭了多个consumer嵌套的可能性。