微信号:DianrongMafia

介绍:点融黑帮——一个充满激情和梦想的技术团队,吸引了来自金融及信息科技领域的顶尖人才.我们正在用技术创新改变传统金融.

React 中使用context实现数据穿越

2017-10-12 19:00 吴蓉
React的核心思想是 构建可重复使用的组件,将一些通用设计元素如按钮、表单域、布局组件等分解成具有明确界面的可重用的组件,然后像插入普通HTML标签一样在网页中插入这个组件。组件使得代码可以重用,这样当需要构建一些UI时,可以编写更少的代码,这意味着更快的开发时间和更少的错误。 React拥有较高的性能,代码逻辑较简单,越来越多的人开始关注和使用它。


☞ 一个简单的react组件示例:


下面的代码展示了一个名为Greeting的组件,其中使用es6语法,组件的render方法用于输出组件的内容,其中render方法返回的组件只能含有一个顶层标签否则会报错。组件封装好了之后,在页面中像插入普通DOM节点一样插入 即可。这里的 是虚拟DOM节点,当组件插入到文档之后便生成真实的DOM。读到这里你就会使用react了,是不是很简单呢。



上面的代码中的this.props.name指的是name属性,props是Greeting组件从外部获取数据的通道。如果需要给组件传递数据,就定义props吧,然后在组件内部通过this.props.属性名的方式获取数据。


☞ 对比Props与context传递数据的方式:


React可以轻松地通过组件来跟踪数据流,上面介绍了使用props在组件之间传递数据,props传递数据简单清晰,很容易看到正在传递数据信息如图一所示。组件A与组件C之间通信,C想获得A中的data数据,则需要通过props先将数据传递到组件B,B再通过props将数据传递到C。



使用props传递数据可以清晰看到数据流向,但是跨级传递非常麻烦。随着应用结构越来越复杂,组件嵌套层次越来越深,有时甚至需要将数据从最外层传递到最里层,使用props则需要一层一层地逐层传递数据。不过这样也太麻烦了,如果有一种方法实现数据穿越就方便多啦。context能够做到这一点,它使得props不用流经组件树的每一层,将数据跨级传递到你想要传递到的深层次组件,如图二所示.


下面定义三个组件分别是MessageList,Message,Button,其中MessageList组件是Message的父组件,Message是Button的父组件.MessageList中的数据text,color,分别用props和context传递给组件Button.组件的之间的层级关系以及数据传递示意图分别如图三,图四所示.



完整的码结构及渲染结果如图五所示:



getChildContext: 该方法表示该组件使用context传递数据,该方法返回的对象就是context需要传递的数据.

childContextTypes: 用于说明所传递的数据类型,上例中color为string类型

contextTypes: 在子组件中用于说明context接收的数据类型

上例中MessageList中的数据text通过props先传递到组件Message,再传递到组件Button.使用context传递数据color就简洁多了,MessageList通过context将数据color直接跨级传递给Button,Button中使用this.context.color就可以得到最外层组件的数据,而不用通过父组件来获取外层数据了。通过将childContextTypes和getChildContext添加到MessageList(上下文提供程序),React将自动传递信息,子树中的任何组件(在本例中为Button)都可以通过定义contextTypes来访问它。


☞使用context实现任意两组件通信:


上面介绍的是父子组件之间的通信,如果两个组件不是父子关系,通过props可以完成数据传递,同样使用context也能办到。实现思路都是让其中一个组件改变两组件的共同父组件state的值,然后通过context将state中的数据传到另一组件。如图六所示,点击SetColorButton组件设置Button组件的颜色。



需要定义一个新组件setColorButton,该组件通过contextTypes接收来外层组件MessageList的setColor方法,setColor方法用于改变外层组件MessageList的state中的color值。setColorButton代码如图七所示:



实现效果如图八所示.



调整MessageList代码,将传递的数据color放在MessageList的state中,当点击setColorButton中的按钮时MessageLIst中state值也跟着改变,从而导致MessageList重新调用render方法,Button组件通过context获取color值也随之更新,从而改变Button按钮的颜色,完整的代码请参考文章末尾。


☞总结:


React中的context和全局变量相似,只有正真全局的东西才合适放在context中,如隐式的传递用户的登录信息。Context会使组件的复用性降低,因为这些组件依赖上下文,在其他地方渲染的时候可能会出现差异,同时组件之间的数据流动变得不够清晰,所以应该谨慎使用context。


  ☞附录:

class SetColorButton extends React.Component {
  render() {
    return (
      <button onClick={this.context.setColor}>
       Click Me(setColor)
      </button>)
  }
}

SetColorButton.contextTypes = {
  setColor:React.PropTypes.func
}

class Button extends React.Component {
  render() {
    return (
      <button style={{background: this.context.color}}>
       {this.props.text}
      </button>)
  }
}

Button.contextTypes = {
  color: React.PropTypes.string
};

class Message extends React.Component {
  render() {
    return (
     <div>
      this is a message 
      <Button text={this.props.text}/>
     </div>);
  }
}

class MessageList extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      color: '#f1bd8b'
    }
  }
  getChildContext() {
    return {
      color: this.state.color,
      setColor: ()=>{this.setState({color: '#a5cdec'})}
    }
  }
  render() {
    const children = this.props.messages.map((ms) =>
      <Message text={ms.text}/>
    )
    return <div> {children} <SetColorButton/></div>;
  }
}

MessageList.childContextTypes = {
  color: React.PropTypes.string,
  setColor: React.PropTypes.func
};

ReactDOM.render(<MessageList messages={[{text: 'button1'},{text: 'button2'},{text: 'button3'}]} />, mountNode);




点击回顾往期精彩内容

帮助你发现问题核心本质的简易方法

Python3异步编程

python音频库dejavu原理浅析

今天我们来聊聊公司估值

python音频库dejavu原理浅析

那些工程师们玩的聚会桌游

从Java看字符编码

浅析Spring AOP

香港金融科技周即将开启,点融成为钻石赞助商

Vue世界中的Redux——Vuex

点融荣登“中国网贷先锋榜”

Affordance杂谈

浅谈金融类APP测试

今天我们来谈谈信息收集这件小事

用Django编写后端任务流程

Webpack优化 | 快一点,再快一点



想了解更多请关注我们



 
点融黑帮 更多文章 帮助你发现问题核心本质的简易方法 Python3异步编程 如何利用大数据来解决中国的巨大的信贷差距问题 python音频库dejavu原理浅析 视错觉与UI元素间的可能
猜您喜欢 入 linode 之前 你所不知道的一件Bra的大数据 ‘DevOps的三板斧’领导交流专用版 开源运动的领袖人物Eric Raymond对于几大开发语言的评价 Mysql max_allowed_packet 被修改设置为1GB或者1024B原因