一、上下文的概念
上下文 (Context) 是 React 中一个重要的特性,它允许您在组件树中共享数据,而不必通过每个级别显式地传递参数。这是一种将数据传递到树中任意深度的组件的方法,无论其祖先组件是否知道该数据。
二、上下文的特点
1、跨级传递数据:Context 允许您在组件树中任意深度传递数据,而不必每层手动传递 props。
2、避免多余的层次:通过 Context,您可以避免将数据传递到组件树中不需要它的组件。
3、易于管理:Context 允许您在一个地方管理数据,而不必在每个组件中手动管理
三、参数介绍
1、createContext
创建一个 Context 对象。当 React 渲染一个订阅了这个 Context 对象的组件,这个组件会从组件树中离自身最近的那个匹配的 Provider 中读取到当前的 context 值。
只有当组件所处的树中没有匹配到 Provider 时,其 defaultValue 参数才会生效。这有助于在不使用 Provider 包装组件的情况下对组件进行测试。注意:将 undefined 传递给 Provider 的 value 时,消费组件的 defaultValue 不会生效
// 这个例子创建了一个名为 MyContext 的 Context 对象。
const MyContext = React.createContext();
2、Provider
每个 Context 对象都会返回一个 Provider React 组件,它允许消费组件订阅 context 的变化。
Provider 接收一个 value 属性,传递给消费组件。一个 Provider 可以和多个消费组件有对应关系。多个 Provider 也可以嵌套使用,里层的会覆盖外层的数据。
// 在我们程序的根节点提供了一个全局对象,对象连具有color属性
class App extends React.Component {
render () {
return (
<MyContext.Provider value={{ color: 'red' }}>
<Child />
</MyContext.Provider>
);
}
}
3、Consumer
用于消耗并渲染 context 数据。
class App extends React.Component {
/*
这里,React 组件也可以订阅到 context 变更。
这能让你在函数式组件中完成订阅 context。
*/
render () {
return (
<MyContext.Consumer>
{({ color }) => (
// 这里可以正常返回jsx代码
<div style={{ color }}>
Hello World!
</div>
)}
</MyContext.Consumer>
);
}
}
四、使用场景
1、主题色切换。
2、多国语言切换。也就是国际化
3、祖孙组件之间的传值
五、例子
使用context完成祖孙传值
1、父组件
import React from "react";
import LearnContext2 from "./LearnContext2";
const MyContext = React.createContext();
export default class LearnContext extends React.Component {
state = {
num: 1,
};
/**
* 接收所有层级的子组件返回的消息
* @param {} msg
*/
getChildData = (msg) => {
console.log(msg);
};
render() {
return (
<div>
<div>父级组件</div>
<MyContext.Provider
/**
* 给所有的子级组件传一个num的值
* 并且传一个方法 让他们也可以和父级组件通讯
*/
value={{ num: this.state.num, getChildData: this.getChildData }}
>
<LearnContext2></LearnContext2>
</MyContext.Provider>
</div>
);
}
}
2、子组件
import React from "react";
import LearnContext3 from "./learn-context3";
export default class LearnContext2 extends React.Component {
render() {
return (
<div>
<div>子组件</div>
<LearnContext3></LearnContext3>
</div>
);
}
}
3、孙组件
使用 Consumer 接收传下来的context
import React from "react";
import { MyContext } from "./learn-context";
class LearnContext3 extends React.Component {
render() {
return (
<MyContext.Consumer>
{/*
直接使用Consumer
这种方式获取参数
但是这种方式 不方便在render意外的地方使用传下来的参数
*/}
{(context) => (
<div>
<div>孙组件</div>
<div>爷爷——传下来的{context.num}</div>
<button onClick={() => context.onChildHandle('哈喽爷爷')}>给爷爷问声好</button>
</div>
)}
</MyContext.Consumer>
);
}
}
export default LearnContext3;
使用contextType 接收context
import React from "react";
import { MyContext } from "./learn-context";
class LearnContext4 extends React.Component {
// 可以直接在类里面使用static 声明静态属性
static contextType = MyContext
render () {
return (
<div>
<div>孙组件</div>
{/*
当我们把context挂载到当前组件的contextType的时候
就可以直接使用this.context拿到相关的值
*/}
<div>爷爷——传下来的{this.context.num}</div>
<button onClick={() => this.context.onChildHandle('哈喽爷爷')}>给爷爷问声好</button>
</div>
)
}
}
// 也可以直接在这上面进行赋值
LearnContext4.contextType = MyContext
export default LearnContext4