Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

React 中的新旧 Context 简单对比 #30

Open
rccoder opened this issue Feb 25, 2018 · 0 comments
Open

React 中的新旧 Context 简单对比 #30

rccoder opened this issue Feb 25, 2018 · 0 comments
Labels

Comments

@rccoder
Copy link
Owner

rccoder commented Feb 25, 2018

妈妈,我再也不会滥用 Redux 了

前言

context 是各种前后端框架中经常会用到的一个概念,著名 Node 框架 Koa 更是把 context 玩的尽兴。React 在很早之前就有 context 的概念,虽然是一个实验性质的 API,但 react-redux、react -router 等框架类库却把它玩了个够。

React 中爷爷和孙子,甚至是重孙之间传递值或者事件一直是个比较麻烦的事情,随着 Redux 等状态管理类库的出现,大家纷纷开始用这种框架去解决这种隔代传信息的问题,并且在或大或小的项目中都开始使用。

一回喜,二回忧,在前端视资源体积为金子的情况下 “滥用 Redux” 的情况越来越多。

React 新版本中的 context 终于要转正了,并且经过了重新的思考与沉淀,与之前 context 在设计哲学上不一样,但解决的却是同一个问题。这样,或许数据流真的不是很多的项目或许可以真的摆脱一下 Redux 等去试试自带的 Context 了。

本文将介绍新老 Context 的一些用法和自己的一些思考。

子孙传值问题

首先看一下最简单的 爷爷给孙子 传值的问题:

class Children extends React.Component {
  render() {
    return (
      <div>{ this.props.text }</div>
      )
    }
}

class Parent extends React.Component {
  render() {
    return (
      <Children text="this.props.text"/>
     )
  }
}

class GrandParent extends React.Component {
  render() {
    return (
      <Parent text="Hi, my baby"/>
    )
  }
}

这几行代码中都是手动的让 text 一辈一辈 的往下传,如果是传给重孙的话还需要继续手动往下传。

利用 Context 就能让这种信息自动的传递,不再让 中间辈 去担任消息传递人,做一些没太大意义的事。

老 Context

const PropTypes = require('prop-types');

class Children extends React.Component {
  static contextTypes = {
    text: PropTypes.string
  }
  render() {
    return (
      <div>{ this.context.text }</div>
    )
  }
}

class Parent extends React.Component {
  render() {
    return (
      <Children/>
    )
  }
}

class GrandParent extends React.Component {
  static childContextTypes = {
    text: PropTypes.string,
  }
  getChildContext() {
    return {
      text: 'Hi, my baby'
    }
  }
  render() {
    return (
      <Parent text="Hi, my baby" />	
    )
  }
}

GrandParent 上通过 getChildContext 给 context 对象添加了 text 的属性,这个属性可以在 GrandParent 的任何一个子孙(子组件)中访问。

同时,为了方便在各种生命周期中使用 context,部分生命周期都给 context 留了接口,具体可以参考 Referencing Context in Lifecycle Methods

新 Context

老式的 context 和依靠中间辈一层层去传递数据相比确实是酷酷的,但总感觉不 React。或许这也是为什么之前一直不建议使用的原因吧。

同时还有一个比较🤢的 context 更新问题,更多可以参考 How to safely use React context

在 React 16.3 中 新版本的 Context 出炉了,感兴趣的可以参考 rfc提案

新版 context 之下上面的代码这样写:

const AppContext = React.createContext();


class Children extends React.Component {
  render() {
    return (
      <AppContext.Consumer>
        {
          context => {
            return (
              <div>{context.text}</div>
            )
          }
        }
       </AppContext.Consumer>
     )
   }
}

class Parent extends React.Component {
  render() {
    return (
      <Children />
    )
  }
}

class GrandParent extends React.Component {
  render() {
    return (
      <AppContext.Provider
        value={{
          text: 'Hi, my baby'
        }}
       >
         <Parent />
       </AppContext.Provider>
     )
   }
}

新版 Context 用 createContext 去初始化一个 context,返回的对象中有 providerconsumer 方法。provider 是以外层容器的方式去包裹住 context 要作用的最外层组件(使用过 Redux 的同学对这点应该有种似曾相似的感觉),然后需要使用到 context 的时候需要用 consumer 去包裹一下。需要注意的是 consumer 包裹的里面的写法,不是普通的组件。

虽然 context 可以是一个 Object,但还是避免不了业务逻辑中会出现多个 context 的问题,consumerprovider 一一对应的模式会造成花式嵌套地狱,可以使用伟大社区产生的 react-context-composer 对 context 进行 composer,源码也非常简单易懂。

Context 会让 Redux 消失吗?

不会,解决的终极问题不完全一样!

Redux 解决的是大型软件架构中数据流传输的问题;context 解决的是子孙之间方便数据交互的问题。有一定的相似性,但不属于同等性质。

延伸阅读

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant