brunoyang/blog

Context,React中隐藏的秘密!

brunoyang opened this issue · 14 comments

好吧我承认我是标题党,新人为了导流量蛮拼的。今天我想给大家介绍一下React中的context,本文基于React@0.14。

重要声明:context 相关内容在将来仍有可能会发生变动,所以不建议使用在生产环境中。

什么是context

context是一个将被收录进React1.0的特性,但目前还没有正式地出现在官方文档中。

那什么是context呢,context就是一组属性的集合,并被_隐式_地传递给后代组件。

大家可能会有疑惑,我们不是已经有了props了吗,为什么还需要用context来传递属性呢。可以考虑这么一个情景,有一个层级很深的组件,最里层组件的行为将影响最外层的表现,一般来说我们就会在最外层组件上绑定回调,再一级一级地传入至最内层组件上,通过触发回调来进行上述行为(这里不考虑用flux)。再考虑另外一个情景,在服务端有一个组件需要根据session来渲染,当内部组件需要获取session信息时,就需要从最上层节点一层一层地往下传。但这样的实现不得不说实在有些丑陋,有没有更好的实现方式呢?有,就是使用context

实例

import ReactDOM from 'react-dom';
import React from 'react'

// Children component
class Children extends React.Component {
  constructor(props, context) {
    super(props, context);

    this.state = {
      name: this.context.name
    };
  }

  render() {
    return(
      <ul>
        <li>
          {`child context is: ${this.context.age}`} // child context is: 18
        </li>
        <li>
          {`state from context: ${this.state.name}`} // state from context: mars
        </li>
        <li>
          {`print age: ${this.context.print(this.context.age)}`} // print age: 18
        </li>
      </ul>
    );
  }
}

Children.contextTypes = {
  name: React.PropTypes.string,
  age: React.PropTypes.number,
  print: React.PropTypes.func
};


// Parent component
class Parent extends React.Component {
  getChildContext() {
    return {
      name: 'mars',
      age: 18
    };
  }

  render() {
    return (
      <div>
        {`from App component: ${this.context.name}`} // from App component: bruno
        <div>
          {this.props.children}
        </div>
      </div>
    );
  }
}

Parent.contextTypes = {
  name: React.PropTypes.string
};
Parent.childContextTypes = {
  age: React.PropTypes.number,
  name: React.PropTypes.string
};

// App component
class App extends React.Component {
  getChildContext() {
    return { 
        name: 'mars',
        print: (m) => m
     };
  }

  render() {
    return (
      <Parent>
        <Children />
      </Parent>
    );
  }
}

App.childContextTypes = {
  name: React.PropTypes.string,
  print: React.PropTypes.func
};

ReactDOM.render(<App />, document.getElementById('app'));

在上面的例子中,我们可以看到在App组价中声明的print方法并没有通过Parent传递,而是通过context直接传递给了Children,这大大方便了我们传值的操作,不再需要一遍一遍地写print={this.props.print}。但同时,我们也需要注意,不要将所有东西都绑定在context上,而是只在必要时使用context,毕竟全局变量很危险。

使用方法

使用getChildContext方法将属性传递给子组件,并使用childContextTypes声明传递数据类型,子组件中需要显式地使用contextTypes声明需要用到的属性的数据类型。

需要传递进context参数才可以在constructor方法中使用context,要不然React将会报错。

在组件中,通过this.context访问context中的属性或方法。

相关api

contextTypes

当需要在当前组件使用从上级组件传入的context的属性时,需要为用到的属性声明数据类型

childContextTypes

声明传递给子组件的属性的数据类型。

getChildContext

设置传递给子组件的属性,可以覆盖,也可以新增。

Thanks!

Thanks!

Thanks

thanks

好吧,我承认你是标题党

还有一个属性updater

function ReactComponent(props, context, updater) {
  this.props = props;
  this.context = context;
  this.refs = emptyObject;
  // We initialize the default updater but the real one gets injected by the
  // renderer.
  this.updater = updater || ReactNoopUpdateQueue;
}

thanks

thanks!! It confused me long time!

ahonn commented

@chenyulun updater 是内部更新的时候使用的。传入自定义的 updater 的话,基本上说明没有什么必要用 react 了...

thanks!!正好用到这个!

thanks

╰(´︶`)╯♡ 写得很清楚,理解了~

Fiv5 commented

thx

thanks a lot