愚墨的博客
  • 首页
  • 前端技术
  • 面试
只争朝夕不负韶华
  1. 首页
  2. 前端框架
  3. React
  4. 正文

Context 使用解析

2019年01月25日 3418点热度 0人点赞 0条评论

context

(上下文)个人理解就是当前环境

首先它是一个属性的有序序列, 并且可以驻留在环境里

有点像全局变量

存在于React 中

react 数据流

单项数据流 ,单纯在React 中

组件内 通过state交流。 父子组件通过props 传递

为了解决 层级传递的繁琐, 于是有了 context ,

Context 旨在解决组件间的数据传递(Super-->Sub 间)

版本 情况

React 16.3 之前 只有 老版context API ,之后老版和新版(createContext)都有。共存。

写法差异

context 提出了一个概念 就是 数据的提供者 和 消费者

这个在新旧API 中 有不同的实现方式

1.老版本的context

Super

  • getChildContext 根组件中声明一个函数,返回一个对象,就是context
  • childContextTypes 根组件中声明,指定context的结构类型,如不指定,会产生错误

Sub

  • contextTypes 子孙组件中声明,指定要接收的context的结构类型,可以只是context的一部分结构。contextTypes 没有定义,context将是一个空对象。
  • this.context 在子孙组件中通过此来获取context
  • 无状态组件 声明一个contextTypes,然后第二个参数 就是context

2.新版本的context

  • 新版本的React context使用了Provider和Customer模式, 更加明确了提供者 和消费者的概念 。和redux-react的模式非常像。
  • 使用 createContext() API 来创建一个Context 对象
 const Context = createContext(defaultValue)
  • 在顶层组件中使用
    <Context.Provider value={context}>
        ...
    </Context.Provider>
  • 在需要使用context的子级中,使用render props的方式来使用
    <Context.Consumer>
        {
            (value)=>{
                return (
                    <>
                        <div>{value}<div>
                    </>
                )
            }
        }
    </Context.Consumer>

看呆萌 ---> old + new

生命周期中的使用

old Context

在old Context中,context不止存在于this.context 中, 在如下生命周期中都可以访问到。前提是你声明了contextTypes

  • constructor(props, context)
  • componentWillReceiveProps(nextProps, nextContext)
  • shouldComponentUpdate(nextProps, nextState, nextContext)
  • componentWillUpdate(nextProps, nextState, nextContext)

从React 16开始,componentDidUpdate不再收到prevContext。

new Context

在新的context 中 不提倡从生命周期中获取context ,在生命周期方法中从context访问值是一种相对常见的用例。而不是将上下文添加到每个生命周期方法中。 只需要将它作为一个 props 传递,然后像通常使用 props 一样去使用它。

like this

  <Context.Consumer>
    {theme => <Button {...props} theme={theme} />}
  </Context.Consumer>
  
  class Button extends React.Component {
  render() {
    const {theme} = this.props;
    return (
      <button className={theme ? 'dark' : 'light'}>
        ...
      </button>
    );
  }
}

使用中的问题

old Context

1、如果顶层组件的context改变,并且我们使用setState 来更新context(只有setState重新render,才能调用getChildContext分发context) ,会导致所有子组件(中间组件)重新加载。

一贯的做法是使用 SCU 或者 PureComponent

React.PureComponent

React.PureComponent类似于React.Component。它们之间的区别在于React.Component它没有实现shouldComponentUpdate(),而是React.PureComponent通过浅的prop和state比较来实现它。

呆萌展示 ---> 改一下oldContext

但是导致新的问题,context 传递不下去。

现有的原生 Context API 存在着一个致命的问题那就是在 Context 值更新后,顶层组件向目标组件 props 透传的过程中 如果中间某个组件的 shouldComponentUpdate 函数返回了 false,因为无法再继续触 发底层组件的 rerender。新的 Context 值将无法到达目标组件。这样的不确定性对于目标组件来说是完全不可控的 也就是说目标组件无法保证自己每一次都可以接收到更新后的 Context 值。

解决办法 :

  • 使用redux、mobx 等 状态管理工具 ---> 废话。
  • 使用新版Context API

新版中间层组件可以使用SCU 或者PureComponent来优化性能,同时还不妨碍context 的传递。

新版context数据可以关联,是因为都源于同一个context对象

new Context

暂且没找到什么明显的缺点

优点

old Context

  • 可中途上车--> 呆萌 中途上车

new Context

  • 中间组件SCU 不会阻断context
  • 泾渭分明 :多个context之间互不影响

如何安全的使用context?

https://medium.com/@mweststrate/how-to-safely-use-react-context-b7e343eff076

1、context只使用一次,就是在初始化的时候,后续不要再更改了

2、如果想改变,使用依赖注入的方式,使用context 在初始化的时候 将依赖注入,并且后期更新可以使用 forceUpdate 来更新,或者将context存于state 中,回调执行setState 来更新组件。(可以将oldContext改成和new Context 一样的优点)

react-redux 等使用此类方法

我们不应该直接在我们的context中存储状态。相反,我们应该使用context作为依赖注入系统。

看呆萌

原理就是 通过将context 的使用限制改为依赖注入而不是 react 本身的状态容器

react 官方原则是 使用context 最好只使用一次,就是初始化的时候

这波操作可以达到的目的是 中间组件可以使用pureComponent 或者 SCU 来避免更新,同时 context 的consumer 还能更新。

上面的如果使用mobx 等 可以直接将 事件发射器 换成 observable 就ok 具体看 pageD/mobx.js

React.PureComponent

React.PureComponent类似于React.Component。它们之间的区别在于React.Component它没有实现shouldComponentUpdate() 需要我们自己来实现,而是React.PureComponent通过浅比较props和stete 来确定是否更新

标签: 暂无
最后更新:2020年08月25日

愚墨

保持饥渴的专注,追求最佳的品质

点赞
< 上一篇
下一篇 >

文章评论

取消回复

搜搜看看
历史遗迹
  • 2023年5月
  • 2022年9月
  • 2022年3月
  • 2022年2月
  • 2021年12月
  • 2021年8月
  • 2021年7月
  • 2021年5月
  • 2021年4月
  • 2021年2月
  • 2021年1月
  • 2020年12月
  • 2020年11月
  • 2020年9月
  • 2020年7月
  • 2020年5月
  • 2020年4月
  • 2020年3月
  • 2020年1月
  • 2019年5月
  • 2019年3月
  • 2019年2月
  • 2019年1月
  • 2018年9月
  • 2018年3月
  • 2018年2月
  • 2018年1月
  • 2017年11月
  • 2017年7月
  • 2017年6月
  • 2017年3月
  • 2017年2月
  • 2017年1月
  • 2016年12月
  • 2016年11月
  • 2016年9月
  • 2016年8月
  • 2016年7月
  • 2016年6月
  • 2016年5月
  • 2016年4月
  • 2016年3月
  • 2016年2月
  • 2016年1月
  • 2015年12月
  • 2015年10月
  • 2015年9月
  • 2015年7月
  • 2015年6月
  • 2015年4月

COPYRIGHT © 2020 愚墨的博客. ALL RIGHTS RESERVED.

THEME KRATOS MADE BY VTROIS