- 由父组件向子组件传递数据的时候通常我们通过 props 来进行传递, 但是在父组件向子组件的子孙组件传递数据用 props 来进行传递时就比较麻烦,会产生冗余代码。那么有没有其他方式呢,今天我们就介绍一下使用 context 来传递,
Context
- context 提供了一种在组件之间共享此类值的方式,而不必显示地通过组件树的逐层传递 props, context 设计目的是为了共享那些对于一个组件数而言是全局的数据,例如主题或者语言。
React.createContext
- 创建一个需要共享的Context对象:
- 如果一个组件订阅了Context,那么这个组件会从离自身最近的那个匹配的 Provider 中读取到当前的context值;
- defaultValue是组件在顶层查找过程中没有找到对应的Provider,那么就使用默认值
Context.Provider
- 每个 Context 对象都会返回一个 Provider React 组件,它允许消费组件订阅 context 的变化:
- Provider 接收一个 value 属性,传递给消费组件;
- 一个 Provider 可以和多个消费组件有对应关系;
- 多个 Provider 也可以嵌套使用,里层的会覆盖外层的数据;
- 当 Provider 的 value 值发生变化时,它内部的所有消费组件都会重新渲染;
Class.contextType
- 挂载在 class 上的 contextType 属性会被重赋值为一个由 React.createContext() 创建的 Context 对象:
- 这能让你使用 this.context 来消费最近 Context 上的那个值;
- 你可以在任何生命周期中访问到它,包括 render 函数中;
Context.Consumer
- 这里,React 组件也可以订阅到 context 变更。这能让你在 函数式组件 中完成订阅 context。
- 这里需要 函数作为子元素(function as child)这种做法;
- 这个函数接收当前的 context 值,返回一个 React 节点;
类组件使用 context 进行跨组件传递数据
具体步骤如下:
- 首先,我们要使用 React.createContext 创造 context, 如下我们创造一个 UserContext ,这个名字自己定义,
const UserContext = React.createContext({ //设置初始值,如果没找到 Provider 就使用初始值
nickname: "张三",
level: 0
})
- 然后使用 xxxContext.Provider 将父组件包裹, 注意 value 属性一定要给, 给它设置的值就是要传递的数据
<UserContext.Provider value={this.state}>
<Profile />
</UserContext.Provider>
-
再然后就是将UserContext赋值给要接收数据的孙组件的 contextType,
ProfileHeader.contextType = UserContext
-
最后,我们就可以在孙组件中使用 this,context.属性名来获取传过来的值了
<div>
<h2>用户昵称: {this.context.nickname}</h2>
<h2>用户等级: {this.context.level}</h2>
</div>
完整代码如下:
import React, { Component } from 'react';
// 创建Context对象
const UserContext = React.createContext({
nickname: "张三",
level: 0
})
class ProfileHeader extends Component {
render() {
return (
<div>
<h2>用户昵称: {this.context.nickname}</h2>
<h2>用户等级: {this.context.level}</h2>
</div>
)
}
}
ProfileHeader.contextType = UserContext;
function Profile(props) {
return (
<div>
<ProfileHeader />
<ul>
<li>设置1</li>
<li>设置2</li>
</ul>
</div>
)
}
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
nickname: "kobe",
level: 99
}
}
render() {
return (
<div>
<UserContext.Provider value={this.state}>
<Profile />
</UserContext.Provider>
</div>
)
}
}
- 如果多个嵌套使用时,同样使用
UserContext.Consumer
,同函数式组件中的嵌套使用,使用UserContext.Consumer
嵌套时,不需要再对 contextType 赋值了
class ProfileHeader extends Component {
render(){
return (
<UserContext.Consumer>
{
value => {
return (
<ThemeContext.Consumer>
{
theme => {
return (
<div>
<h2 style={{color: theme.color}}>用户昵称: {value.nickname}</h2>
<h2>用户等级: {value.level}</h2>
<h2>颜色: {theme.color}</h2>
</div>
)
}
}
</ThemeContext.Consumer>
)
}
}
</UserContext.Consumer>
)
}
}
函数式组件使用 context 进行跨组件传递数据
具体步骤如下:
- 首先,我们要使用 React.createContext 创造 context, 如下我们创造一个 UserContext ,这个名字自己定义,
const UserContext = React.createContext({ //设置初始值
nickname: "张三",
level: 0
})
- 然后使用 xxxContext.Provider 将父组件包裹, 注意 value 属性一定要给, 给它设置的值就是要传递的数据
<UserContext.Provider value={this.state}>
<Profile />
</UserContext.Provider>
- 最后在孙组件中使用UserContext.Consumer将传递的数据取出来
function ProfileHeader() {
return (
<UserContext.Consumer>
{
value => {
return (
<div>
<h2>用户昵称: {value.nickname}</h2>
<h2>用户等级: {value.level}</h2>
</div>
)
}
}
</UserContext.Consumer>
)
}
- 如果是多个时嵌套使用即可,这么我们再增加一个ThemeContext来嵌套演示。
- 创建 ThemeContext
const ThemeContext = React.createContext({
color: "black"
})
- UserContext和ThemeContext嵌套包裹父组件
<UserContext.Provider value={this.state}>
<ThemeContext.Provider value={{ color: "red" }}>
<Profile />
</ThemeContext.Provider>
</UserContext.Provider>
- 在孙组件中嵌套取值
function ProfileHeader() {
return (
<UserContext.Consumer>
{
value => {
return (
<ThemeContext.Consumer>
{
theme => {
return (
<div>
<h2 style={{color: theme.color}}>用户昵称: {value.nickname}</h2>
<h2>用户等级: {value.level}</h2>
<h2>颜色: {theme.color}</h2>
</div>
)
}
}
</ThemeContext.Consumer>
)
}
}
</UserContext.Consumer>
)
}
- 完整代码如下:
import React, { Component } from 'react';
// 创建Context对象
const UserContext = React.createContext({
nickname: "aaaa",
level: -1
})
const ThemeContext = React.createContext({
color: "black"
})
function ProfileHeader() {
// jsx -> 嵌套的方式
return (
<UserContext.Consumer>
{
value => {
return (
<ThemeContext.Consumer>
{
theme => {
return (
<div>
<h2 style={{color: theme.color}}>用户昵称: {value.nickname}</h2>
<h2>用户等级: {value.level}</h2>
<h2>颜色: {theme.color}</h2>
</div>
)
}
}
</ThemeContext.Consumer>
)
}
}
</UserContext.Consumer>
)
}
function Profile(props) {
return (
<div>
<ProfileHeader />
<ul>
<li>设置1</li>
<li>设置2</li>
<li>设置3</li>
<li>设置4</li>
</ul>
</div>
)
}
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
nickname: "kobe",
level: 99
}
}
render() {
return (
<div>
<UserContext.Provider value={this.state}>
<ThemeContext.Provider value={{ color: "red" }}>
<Profile />
</ThemeContext.Provider>
</UserContext.Provider>
</div>
)
}
}
- 注意由于类组件的contextType只能设置一个值,所以不能嵌套,后设置的会把前设置的覆盖掉
网友评论