React Context 的基本用法

Context 提供了一个无需为每层组件手动添加 props,就能在组件树间进行数据传递的方法。

1. 用法

React.createContext

const MyContext = React.createContext(defaultValue);

创建一个 Context 对象。当 React 渲染一个订阅了这个 Context 对象的组件,这个组件会从组件树中离自身最近的那个匹配的 Provider 中读取到当前的 context 值。

只有当组件所处的树中没有匹配到 Provider 时,其 defaultValue 参数才会生效。这有助于在不使用 Provider 包装组件的情况下对组件进行测试。注意:将 undefined 传递给 Provider 的 value 时,消费组件的 defaultValue 不会生效。

Context.Provider

<MyContext.Provider value={/* 某个值 */}>

每个 Context 对象都会返回一个 Provider React 组件,它允许消费组件订阅 context 的变化。

Provider 接收一个 value 属性,传递给消费组件。一个 Provider 可以和多个消费组件有对应关系。多个 Provider 也可以嵌套使用,里层的会覆盖外层的数据。

Context.Consumer

<MyContext.Consumer>
  {value => /* 基于 context 值进行渲染*/}
</MyContext.Consumer>

这里,React 组件也可以订阅到 context 变更。这能让你在函数式组件中完成订阅 context。

2. 实例应用

image

如图,在父组件中定义两个变量:fruit 和 count。子组件可以拿到父组件的fruit,子子组件可以拿到父组件的 fruit,并且可以改变count的值。

实现步骤如下:

2.1 新建文件 context.js

创建一个Context 对象,并导出Provider和Consumer容器。

import { createContext } from 'react'

export const { Provider, Consumer } = createContext()

2.2 新建父组件 index.js

import React, { Component } from 'react'
import { Provider } from './context' // 引入Provider
import Son from './Son' // 引入子组件

class Main extends Component {
  constructor(props) {
    super(props)
    this.state = {
      fruit: 'apple',
      count: 0,
    }
  }

  componentDidMount() {}

  getContext = () => {
    const { fruit, count } = this.state
    return {
      fruit,
      countUtil: {
        addCount: num => {
          this.setState({
            count: count + num,
          })
        },
        delCount: num => {
          this.setState({
            count: count - num,
          })
        },
      },
    }
  }

  render() {
    const { fruit, count } = this.state
    return (
      // Provider 容器, 其value接收一个getContext方法
      <Provider value={this.getContext()}>
        父组件 fruit = {fruit}, count = {count}
        <hr />
        <Son />
      </Provider>
    )
  }
}

export default Main

2.3 新建子组件 Son.js

import React, { Component } from 'react'
import { Consumer } from './context' // 引入Consumer
import GrandSon from './GrandSon' // 引入子子组件

class Main extends Component {
  constructor(props) {
    super(props)
    this.state = {}
  }

  render() {
    return (
      // Consumer 容器,可以拿到父组件传递下来的 fruit 属性, 并可以展示对应的值
      <Consumer>
        {context => (
          <div>
            子组件 fruit={context.fruit}
            <hr />
            <GrandSon />
          </div>
        )}
      </Consumer>
    )
  }
}

export default Main

2.4 新建子子组件 GrandSon.js

import React, { Component } from 'react'
import { Consumer } from './context' // 引入Consumer

class Main extends Component {
  constructor(props) {
    super(props)
    this.state = {}
  }

  render() {
    return (
      // Consumer 容器,可以拿到父组件传递下来的 fruit 属性, 以及 countUtil对象下的 addCount 和 delCount 方法
      <Consumer>
        {context => (
          <div>
            子子组件 fruit={context.fruit}
            <br />
            <button type="button" onClick={() => context.countUtil.addCount(2)}>
              加2
            </button>
            &nbsp;
            <button type="button" onClick={() => context.countUtil.delCount(3)}>
              减3
            </button>
            <hr />
          </div>
        )}
      </Consumer>
    )
  }
}

export default Main

posted @ 2020-04-20 16:15  Mr.曹  阅读(5421)  评论(1编辑  收藏  举报