React-Context
文章目录

React-Context

主要的目的是跨组件通讯。有一些组件之间不是直接的父子关系。并且有一些情况下无法传递 props, 这时候可以考虑 context 来实现

有两种实现方式

  1. childContextType (V17 会废弃)
    • 使用 context 的下层组件全部都会重新渲染, 导致性能比较差
  2. createContext

childContextType (不推荐)

  1. 在父组件里面定义一个 getChildContext()
    1
    2
    3
    4
    5
    getChildContext() {
    return {
    value: this.state.childContext, a: 'aaaaa'
    }
    }
  2. 定义子组件以及父组件的 context 的 propTypes
    • 子组件和父组件都需要定义
    • 没有定义的 attr 将会被忽略
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      // 这里是对于对应的 context 的 attr 的声明
      Child.contextTypes = {
      value: PropTypes.string,
      a: PropTypes.string,
      // 如果这里一个 attr 不声明, 那么就直接会显示为空
      // 比如, 如果没有声明 a, 那么 this.context.a 就无法获取到
      }

      // 在 Parent 里面也要进行对应的声明。
      Parent.childContextTypes = {
      value: PropTypes.string,
      a: PropTypes.string,
      }
  3. 在子组件里面通过 this.context 访问传递过来的 context
    • 如果一个子组件被多个父组件包含,那么他们里面的 context 会被 merge 然后最终传递给子组件。
      1
      2
      3
      4
      5
      6
      7
      8
      9
      class Child extends React.Component {
      render() {
      return (
      <p>
      childContext: {this.context.value} {this.context.a}
      </p>
      )
      }
      }

详细例子: [childContextType 完整例子](#childContextType 完整例子)

流程图解释

流程如下图:

  1. 父组件定义了一个 getChildContext() 然后传 users 给 users
  2. 父组件和子组件的 propTypes 定义了 users 要求是一个 array
  3. 子组件接收到之后就可以访问了
    clipboard.png

createContext

  1. 首先通过 React.createContext() 生成一堆 tuple
    1
    const { Provider, Consumer } = React.createContext('default')
    • 生成的 Provider 和 Consumer 也是一个 component, 并且要注意的是这两个是对应的。
  2. 父组件里面用 Provider 包裹一下 子组件
    1
    <Provider value={this.state.newContext}>{this.props.children}</Provider>
  3. 子组件里面使用 Consumer, 并且这里需要传进去一个方法
    1
    2
    3
    4
    function Child1(props, context) {
    console.log(context)
    return <Consumer>{value => <p>newContext: {value}</p>}</Consumer>
    }

详细例子: [createContext 详细的代码示例](#createContext 详细的代码示例)

附录

childContextType 完整例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
import React from 'react'
import PropTypes from 'prop-types'


class Parent extends React.Component {
state = {
childContext: '123',
newContext: '456',
}

getChildContext() {
return {
value: this.state.childContext, a: 'aaaaa'
}
}

render() {
return (
<>
<div>
<label>childContext:</label>
<input
type="text"
value={this.state.childContext}
onChange={e => this.setState({ childContext: e.target.value })}
/>
</div>
{this.props.children}
</>
)
}
}


// 在 child 里面直接访问就可以使用了。
class Child extends React.Component {
render() {
return (
<p>
childContext: {this.context.value} {this.context.a}
</p>
)
}
}

// 另外也可以使用纯函数式组件, 多传一个参数即可
/*
function Child(props, context) {
console.log(context)
return <Consumer>{value => <p>newContext: {value}</p>}</Consumer>
}
*/

// 这里是对于对应的 context 的 attr 的声明
Child.contextTypes = {
value: PropTypes.string,
a: PropTypes.string,
// 如果这里一个 attr 不声明, 那么就直接会显示为空
// 比如, 如果没有声明 a, 那么 this.context.a 就无法获取到
}

// 在 Parent 里面也要进行对应的声明。
Parent.childContextTypes = {
value: PropTypes.string,
a: PropTypes.string,
}

export default () => (
<Parent>
<span>
<Child />
</span>
</Parent>
)

createContext 详细的代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import React from 'react'
import PropTypes from 'prop-types'

// 通过 createContext 获得 context 的提供方和订阅方
const { Provider, Consumer } = React.createContext('default')

class Parent extends React.Component {
state = {
childContext: '123',
newContext: '456',
}


render() {
return (
<>
<div>
<label>newContext:</label>
<input
type="text"
value={this.state.newContext}
onChange={e => this.setState({ newContext: e.target.value })}
/>
</div>
<Provider value={this.state.newContext}>{this.props.children}</Provider>
</>
)
}
}

class Parent2 extends React.Component {
render() {
return this.props.children
}
}

function Child1(props, context) {
console.log(context)
return <Consumer>{value => <p>newContext: {value}</p>}</Consumer>
}

export default () => (
<Parent>
<Parent2>
<Child1 />
</Parent2>
</Parent>
)