React context 理解

关于react-context的官方文档
https://reactjs.org/docs/context.htmlhtml

原由

不少同窗认为一旦父子组件之间层级过深,多层级通信时候第一反应就是要用vuex和redux,但每每杀鸡用了宰牛刀。可是vue和react中提供了不少方法去达到数据共享的效果,而没必要显式地经过组件树的逐层传递 props。
好比在vue中provide 和 inject前端

一、这对选项须要一块儿使用,以容许一个祖先组件向其全部子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。
二、provide提供数据,多层子组件 向上层寻找,只要找到 就不在向上层寻找了。
三、inject 向子组件注入数据;

vue中的mixin和extend也能够作到相关功能,这里就不作详细赘述,须要了解的同窗能够自行去观看。
下面回到本篇文章的正题react-context,React官网的高级指引中指出了Context,优雅的解决这个问题。vue

context含义

前端同窗都知道在js中的context指的是执行上下文,this指向谁,谁就是当前的执行上下文。react

而react-context是什么呢?react-context官网中第一句就给出了解释:

Context 提供了一个无需为每层组件手动添加 props,就能在组件树间进行数据传递的方法。
意思即是context可以没必要显式地经过组件树的逐层传递 props,能够跨层级进行数据传递。vuex

其实质为跨层级的组件搭建一座桥梁。

context Api

React context的API有两个版本,React16.x以前的是老版本的context,以后的是新版本的context。

先简单说下老版本,以前也是实验性的存在,我以为不太好用。生产者须要声明childContextTypes对象,对类数据类型进行校验,不提供就会报错。
具体的就不细说,须要了解的同窗自行查看。redux

下面回到16.x版本的context,Context是16.3.0正式肯定的API

学习context首先须要了解其三个核心的api: React.createContext()、Provider(发布者)、Consumer(订阅者)api

React.createContext()和Provider

createContext()建立一个 Context 对象。浏览器

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

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

当 Provider 的value值发生变化时,它内部的全部消费组件都会从新渲染。Provider 及其内部 consumer 组件都不受制于shouldComponentUpdate函数,所以当 consumer 组件在其祖先组件退出更新的状况下也能更新。

value的值天然是能够动态变动的,而且会传递给子组件中,点击变动value按钮会发现页面上的三个tomorrow变为三个yesterday。

import React, { useContext } from 'react'

const ThemeContext = React.createContext('today')
class App extends React.Component {
  state = {
    user: 'tomorrow'
  }

  change = () => {
    this.setState({
      user: 'yesterday'
    })
  }

  render() {
    const { user } = this.state
    // createContext默认值是“today”。
    // 不管多深,任何组件都能读取这个值。
    // 这里Provider 把value值 “tomorrow” 做为当前的值传递下去。
    return (
      <ThemeContext.Provider value={ user }>
        <div onClick={ this.change }>变动value</div>
        <Toolbar />
      </ThemeContext.Provider>
    );
  }
}

这里是react-hook函数式写法,用到react-hook的API:useContext获取context的值
挂载在 class 上的contextType属性会被重赋值为一个由React.createContext()建立的 Context 对象。这能让你使用this.context来消费最近 Context 上的那个值。你能够在任何生命周期中访问到它,包括 render 函数中

function Toolbar() {
  const context = useContext(ThemeContext)
  return (
    <div>
      <div>{context}</div>
      <Head />
    </div>
  );
}

Consumer

经过ThemeContext的属性Consumer消费用户数据
Consumer的子组件必须是一个function,经过function的参数接收顶层传入的数据
任何订阅者(Consumer)均可以直接修改context,这会致使后续的订阅者获取到修改后的context值,但这显然是不可取的。
若是须要修改,应该统一由发布者(Provider)修改,也就是相似APP组件中变动value按钮

class Head extends React.Component {
  render() {
    return (
      <ThemeContext.Consumer>
        {
          context => (
            <div>
              <div>{this.context}</div>
              <Title />
            </div>
          )
        }
      </ThemeContext.Consumer>
    )
  }
}

最后的子组件显示context内容
context还有个Api:Context.displayName
想了解的同窗能够去官网看一下

class Title extends React.Component {
  static contextType = ThemeContext
  render() {
    return (
      <div>
        {this.context}
      </div>
    )
  }
}

注意事项

在 provider 的父组件进行重渲染时,可能会在 Consumers 组件中触发意外的渲染。

下面例子:对value直接赋值的时候就会触发这种没必要要的渲染

const ThemeContext = React.createContext();
class App extends React.Component {
  render() {
    return (
      <ThemeContext.Provider value={ {name: '666'} }>
        <div onClick={ this.change }>变动value</div>
        <Toolbar />
      </ThemeContext.Provider>
    );
  }
}

能够经过把value值放在state中解决这种问题

const ThemeContext = React.createContext();
class App extends React.Component {
  state = {
    name: '666'
  }

  change = () => {
    this.setState({
      user: 'yesterday'
    })
  }

  render() {
    const { user } = this.state
    return (
      <ThemeContext.Provider value={ user }>
        <div onClick={ this.change }>变动value</div>
        <Toolbar />
      </ThemeContext.Provider>
    );
  }
}

似曾相识的context -- redux

有没有发现redux的注入和context的注入很是类似。
image.png
经过React Developer Tools在浏览器很容易发现
react-redux其实是经过Provider组件和connect方法进行链接react和redux,那么他们到底本质上就是经过Context来传递数据
WeChatb37598c11cb3bb30ffb2ac7bd28f063c.png

以上就是我的对react-context学习的一点总结。context虽然轻便,可是官方仍是没有大面积的去推广,仍是存在些问题,毕竟和强大的react-redux对比,没有很好的管理体系,普遍认知度也比较低。可是凡事没有绝对好坏,只有适不适合。

相关文章
相关标签/搜索