react中的context
对react context的理解:
为什么使用context
在React中,数据传递一般使用props传递数据,维持单向数据流,这样可以让组件之间的关系变得简单并且可预测,但是单项数据流在某些场景中并不适用。单纯一对的父子组件传递并无问题,但要是组件之间层层依赖深入,props就需要层层传递。显然,这样做太繁琐了
context是什么
Context 提供了一种在组件之间共享值的方式,而不必显式地通过组件树的层层传递 props.
可以把context当做是特定一个组件树内共享的store,用来做数据传递。简单说就是,当你不想在组件树中通过逐层传递props或者state的方式来传递数据时,可以使用Context来实现跨层级的组件数据传递。
context怎么样运行
JS的代码块在执行期间,会创建一个相应的作用域链,这个作用域链记录着运行时JS代码块执行期间所能访问的活动对象,包括变量和函数,JS程序通过作用域链访问到代码块内部或者外部的变量和函数
假如以JS的作用域链作为类比,React组件提供的Context对象其实就好比一个提供给子组件访问的作用域,而Context对象的属性可以看成作用域上的活动对象,由于组件的 Context 由其父节点链上所有组件通过getChildContext ()返回的Context对象组合而成,所以,组件通过Context是可以访问到其父组件链上所有节点组件提供的context属性
context中的API
createContext():
用于创建context对象(上下文),需要一个defaultValue的参数,并返回一个包含Provider(提供者),以及Consumer(消费者)的对象。
Provider:
提供者,提供数据。接收一个将要被往下层层传递的props,该值需在组件树最顶层设置。一个Provider可以关联到多个Consumers。这是一个顶层用于提供context的组件,包含一个value的props,value是实际的context数据。
Consumer:
消费者,使用者,接收一个函数作为子节点,函数接收当前 context 的值。这是一个底层用于获取context的组件,需要一个函数作为其子元素,该函数包含一个value的参数,这个参数就是上层所传递context value
React中context的使用方法
// 引入React
import React, {Component} from 'react';
// 引入样式
import './App.css';
/*
* 详细说明:定义了三个组件:分别为App/AppChild/AppChildChild
* 组件关系:App -> AppChild 父子; App -> AppChildChild 祖;AppChild -> AppChildChild 父子;
* 通过下面案例你将领略context的使用方法
* 使用方法总结:
* 1.先创建一个Context容器对象,可以进行结构Provider及Consumer方便之后的简单应用。
* 2.包裹要用的组件,给谁用就在谁的外面包裹,使用属性关键字value进行传值,value不可改变。
* 3.在哪里使用就在哪里声明,static contextType = 容器对象名字;
* 4.使用 this.content获取
* 注意上述方法只限于类式组件,如果你使用的是函数式组件,那么你应该用下面的方式去做
* <Consumer>
* {
* value => {
* }
* }
* </Consumer>
***/
// 创建一个Context容器对象,注意开头大写
const MyContext = React.createContext()
// 拿出Provider及Consumer
const {Provider, Consumer} = MyContext;
// 定义一个祖组件
class App extends Component {
state = {
username: 'Tom',
age: 20
}
render() {
const {username, age} = this.state;
return (
<div className="App">
<h3>我是App组件</h3>
<h4>我的名字:{username}</h4>
{/*利用props给子组件AppChild传值*/}
{/*给谁用就用Provider包裹*/}
{/*<Provider value={username}>
<AppChild username={username}/>
</Provider>*/}
<Provider value={{username, age}}>
<AppChild username={username}/>
</Provider>
</div>
);
}
}
// 父级组件
class AppChild extends Component {
render() {
const {username} = this.props;
return (
<div className="AppChild">
<h3>我是AppChild组件</h3>
<h4>我接收来自App组件的名字是:{username}</h4>
<AppChildChild/>
</div>
);
}
}
// 子组件-类式声明
/*class AppChildChild extends Component {
// 声明context
static contextType = MyContext;
render() {
const {username, age} = this.context;
return (
<div className="AppChildChild">
<h3>我是AppChildChild组件</h3>
<h4>我接收来自App组件的名字是:{username},年龄:{age}</h4>
</div>
);
}
}*/
// 子组件-函数式声明
function AppChildChild() {
return (
<div className="AppChildChild">
<h3>我是AppChildChild组件</h3>
<h4>
<Consumer>
{
value => {
return `我接收来自App组件的名字是:${value.username},年龄:${value.age}`
}
}
</Consumer>
</h4>
</div>
)
}
export default App;
为什么React并不推荐优先考虑使用Context?
- Context目前还处于实验阶段,可能会在后面的发行版本中有很大的变化,事实上这种情况已经发生了,所以为了避免给今后升级带来大的影响和麻烦,不建议在app中使用context
- 尽管不建议在app中使用context,但是独有组件而言,由于影响范围小于app,如果可以做到高内聚,不破坏组件树之间的依赖关系,可以考虑使用context
- 对于组件之间的数据通信或者状态管理,有效使用props或者state解决,然后再考虑使用第一方的成熟库进行解决,以上的方法都不是最佳的方案的时候,在考虑context
- context的更新需要通过setState() 触发,但是这并不是很可靠的,Context支持跨组件的访问,但是如果中间的子组件通过一些方法不影响更新,比如 shouldComponentUpdate() 返回false 那么不能保证Context的更新定可以使用Context的子组件,因此,Context的可靠性需要关注