引言
在我们React组件开发中,当一个父组件的想要往自己的子孙组件传值的时候,可以使用 props
属性,但是其每一个子组件,都要向下传递数据,这样造成的数据的耦合性,所以在 React 官方文档中 提供了 context
特性来解决,这个问题。
父子组件之间的通信
我们先看一下React中,父子组件通信的机制,父子组件的通信是通过props进行数据的传递:
- 父组件向子组件传递数据(状态)时,是在调用子组件的时候通过参数传递给子组件,子组件通过this.props进行接收;
- 子组件如果更改父组件的一些属性,则是通过父组件定义的方法来传递给子组件,子组件调用更改;
- 如果父组件想要更改子组件的一些状态时,通过ref进行标记,可以获取子组件的所有信息,从而调用子组件的方法和值;
但是,如果层级很多呢,是否需要多个props进行逐层的传递?答案是否定的,React的advanced(高级)中指出了context,优雅的解决这个问题。
好的,接下来我们来介绍一下这个特性Context
我们知道,在JS中context指的是函数的执行上下文,函数被调用时,this指向谁,谁就是当前的执行上下文;
- react中的context是什么呢?官方文档给出:
- Context 通过组件树提供了一个传递数据的方法,从而避免了在每一个层级手动的传递 props 属性。
文档也没具体给出context到底是什么,而是告诉我们context能干什么,也就是说,如果我们不想通过props实现组件树的逐层传递数据,则可以使用context实现跨层级进行数据传递!
如何使用 Context 呢?
context api给出三个概念:React.createContext()、Provider、Consumer;
- React.createContext()
这个方法用来创建context对象,并包含Provider、Consumer两个组件 <Provider />、<Consumer />
const {Provider, Consumer} = React.createContext();
- Provider
数据的生产者,通过value属性接收存储的公共状态,来传递给子组件或后代组件
eg:
<Provider value={/* some value */}>
- Consumer
数据的消费者,通过订阅Provider传入的context的值,来实时更新当前组件的状态
eg:
<Consumer>
{value => /* render something based on the context value */}
</Consumer>
值得一提的是每当Provider的值发生改变时, 作为Provider后代的所有Consumers都会重新渲染
props单向数据流动:
如果觉得Props传递数据很繁琐,可以采用context,进行跨组件传递数据
再最外层的组件上,通过生产者Provider组件进行包裹,并存储共享数据到value中,当然可以是任何数据类型。后带需要用到共享数据的组件均可通过Consumer进行数据获取
代码演示
import React from 'react'
import ReactDOM from 'react-dom'
// 创建一个 textcont 特性的
const {Provider,Consumer} = React.createContext('顶顶顶')
class Person extends React.Component{
constructor(props){
super(props)
this.state = {
color : 'red'
}
}
render(){
return (
<Provider value={this.state.color}>
<h1>我是父组件</h1>
<Son></Son>
</Provider>
);
}
}
class Son extends Person{
render(){
return <div>
<h3>我是子组件</h3>
<Son1></Son1>
</div>
}
}
class Son1 extends Son{
render(){
return (
<Consumer>
{
(color) => <div>
<h6 style={{color}}>我是孙子组件-----{color}</h6>
</div>
}
</Consumer>
);
}
}
ReactDOM.render(<div>
<Person></Person>
</div>,document.getElementById('app'))