React中,通过React组件可以很容易地追踪数据流。当你关注一个组件,你可以发现哪一个props被传递了,这样使得你的应用很容被推断。

在一些情况下,你想要传递数据通过组件树而不需要去手动在每一层传递。你可以直接使用强大的context API。

为什么不使用context

大量的应用不需要使用context。

如果你希望你的应用稳定,不要使用context。这是一个实验性的API在未来的版本中有可能会崩溃。

如果你不熟悉state管理库就类似于Redux或者Mobx,不要使用context。对于很多实际的应用,这些库和它们的React绑定实现是很好的选择来管理state,这对于很多组件都有重大意义。解决问题最好的方案更像是Redux而不是context。

如果你不是一个有经验的React开发者,不要使用context。有更好的方式去实现功能通过使用props和state。

如果你坚持使用context而不管这些警告,那么就请试图隔离你使用context在一个较小的范围并且避免直接使用context API为了当API改变的时候升级方便。

怎样使用context

假设你拥有这样的一个结构:

class Button extends React.Component {
render() {
return (
<button style={{background: this.props.color}}>
{this.props.children}
</button>
);
}
} class Message extends React.Component {
render() {
return (
<div>
{this.props.text} <Button color={this.props.color}>Delete</Button>
</div>
);
}
} class MessageList extends React.Component {
render() {
const color = "purple";
const children = this.props.messages.map((message) =>
<Message text={message.text} color={color} />
);
return <div>{children}</div>;
}
}

在这个例子里,我们手动传递了一个color属性为了让Button和Message组件的有一个合适的样式。使用context,我们可以自动传递属性通过树。

class Button extends React.Component {
render() {
return (
<button style={{background: this.context.color}}>
{this.props.children}
</button>
);
}
} Button.contextTypes = {
color: React.PropTypes.string
}; class Message extends React.Component {
render() {
return (
<div>
{this.props.text} <Button>Delete</Button>
</div>
);
}
} class MessageList extends React.Component {
getChildContext() {
return {color: "purple"};
} render() {
const children = this.props.messages.map((message) =>
<Message text={message.text} />
);
return <div>{children}</div>;
}
} MessageList.childContextTypes = {
color: React.PropTypes.string
};

通过为MessageList组件(context提供者)添加childContextTypes属性和getChildContext方法,React会自动传递信息并且任何子树里的组件(在这个例子,Button组件)都可以获取到这个信息通过定义contextTypes。

如果contextTypes没有定义,那么context会是一个空对象。

父子联合

context也可以让你建造一套可以让父组件和子组件通信的API。举个例子,一个这样运作的库叫做React Router v4

import { Router, Route, Link } from 'react-router-dom';

const BasicExample = () => (
<Router>
<div>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to="/about">About</Link></li>
<li><Link to="/topics">Topics</Link></li>
</ul> <hr /> <Route exact path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/topics" component={Topics} />
</div>
</Router>
);

通过从Router组件传递一些信息,每一个Link和Route都可以和包含的Router通信。

在你使用类似的API创建组件的时候,思考是否有更灵活的替代方案。举个例子,你可以传递整个React组件作为props如果你喜欢。

在生命周期方法里引用context

如果在一个组件内部定义了contextTypes,下面的生命周期方法将会接收一个额外的参数,就是context对象:

  • constructor(props, context)
  • componentWillReceiveProps(nextProps, nextContext)
  • shouldComponentUpdate(nextProps, nextState, nextContext)
  • componentWillUpdate(nextProps, nextState, nextContext)
  • componentDidUpdate(prevProps, prevState, prevContext)

在无状态的函数式组件里引用context

如果在函数里定义了contextTypes作为一个属性,那么也可以在无状态的函数式组件里引用context。下面的代码显示了一个Button组件被写成一个无状态函数式组件。
const Button = ({children}, context) =>
<button style={{background: context.color}}>
{children}
</button>; Button.contextTypes = {color: React.PropTypes.string};

更新context

不要这样做。

React有一个更新context的API,但是它实质上已经损坏你不应该使用它。

getChildContext函数当props或者state改变的时候会被调用。为了在context中更新数据,使用this.setState来触发本地的state更新。这样将会触发一个新的context并且改变会被子组件接收。

class MediaQuery extends React.Component {
constructor(props) {
super(props);
this.state = {type:'desktop'};
} getChildContext() {
return {type: this.state.type};
} componentDidMount() {
const checkMediaQuery = () => {
const type = window.matchMedia("(min-width: 1025px)").matches ? 'desktop' : 'mobile';
if (type !== this.state.type) {
this.setState({type});
}
}; window.addEventListener('resize', checkMediaQuery);
checkMediaQuery();
} render() {
return this.props.children;
}
} MediaQuery.childContextTypes = {
type: React.PropTypes.string
};

问题在于,如果一个组件提供的context值改变了,使用那个值的子节点就不会更新如果中间的组件从shouldComponentUpdate返回了false。这样组件使用context就完全失去了控制,因此基本没有什么方法可以可靠地更新context。这个博客有一个很好地解释关于为什么这是一个问题以及你怎样避开它。

React文档(二十二)context的更多相关文章

  1. React文档(十二)组合vs继承

    React拥有很强大的组合模型,我们建议使用组合来替代继承来重利用组件之间的代码. 在本章节中,我们将讨论一些开发者经常触及继承的问题,并且我们该如何使用组合来解决这些问题. 组合 一些组件事先不知道 ...

  2. React文档(十六)refs和DOM

    Refs 提供了一种方式,用于访问在 render 方法中创建的 DOM 节点或 React 元素. 在标准的React数据流中,props是使得父组件和子组件之间交互的唯一方式.你通过props重新 ...

  3. React文档(十九)不使用ES6

    通常你会将一个React组件定义成一个普通的js类: class Greeting extends React.Component { render() { return <h1>Hell ...

  4. React文档(十八)最佳性能

    在内部,React使用好几种聪明的技巧去最小化更新UI所需要的DOM操作.对于很多应用来说,使用React会使得构建用户界面非常之快而且不需要做太多专门的性能优化.虽然如此,还是有一些方法可以让你为R ...

  5. React文档(十五)使用propTypes进行类型检查

    注意: React.PropTypes 自 React v15.5 起已弃用.请使用 prop-types 库代替. 随着你的应用的开发,你会使用类型检查的方法来捕获很多bug.对于一些应用,你可以使 ...

  6. React文档(十四)深入JSX

    根本上,JSX只是为React.createElement(component, props, ...children)函数提供语法糖.JSX代码是这样的: <MyButton color=&q ...

  7. React文档(十)表单

    HTML表单元素和 React里的其他DOM元素有些不同,因为它们会保留一些内部的状态.举个例子,这个普通的表单接受唯一的name值: <form> <label> Name: ...

  8. Docker最全教程之使用Node.js搭建团队技术文档站(二十三)

    前言 各种编程语言均有其优势和生态,有兴趣的朋友完全可以涉猎多门语言.在平常的工作之中,也可以尝试选择相对适合的编程语言来完成相关的工作. 在团队技术文档站搭建这块,笔者尝试了许多框架,最终还是选择了 ...

  9. JAVA基础知识总结:一到二十二全部总结

    >一: 一.软件开发的常识 1.什么是软件? 一系列按照特定顺序组织起来的计算机数据或者指令 常见的软件: 系统软件:Windows\Mac OS \Linux 应用软件:QQ,一系列的播放器( ...

  10. Alink漫谈(二十二) :源码分析之聚类评估

    Alink漫谈(二十二) :源码分析之聚类评估 目录 Alink漫谈(二十二) :源码分析之聚类评估 0x00 摘要 0x01 背景概念 1.1 什么是聚类 1.2 聚类分析的方法 1.3 聚类评估 ...

随机推荐

  1. Setting NLS_LANG Value for Oracle

    Introduction Many times, when you have an Oracle application and you have to support special charact ...

  2. 透析SOA、RPC、SOAP、REST、ICE、ESB模型发展史

    最初的程序全是单机程序,没有网络,没有RPC,更没有RESTful.程序猿写的东西孤独运行在单机上. 那时的程序猿们语言相通,参与开发同一套系统的团队可以面对面沟通. 网络出现了.网络,也带来变乱.网 ...

  3. Simple Factory Pattern

    Question: How do you achieve the functions of calculator by Object-Oriented ? Analysis: 1,The functi ...

  4. FileOutputSream文件字节输出流

    1.FileOutputSream文件字节输出流:  输入--写出--使用:  输出--写入--存储: 写出写入是对硬盘而言: 其中,OutputStream为所有类型的字节输出流的超类: FileO ...

  5. 博客地址更改为csdn博客:https://blog.csdn.net/zysps1

    由于博客园不支持markdown的数学公式等语法,有时分享不方便,特更改阵地为csdn:https://blog.csdn.net/zysps1

  6. spider爬虫练习

    package com.jinzhi.spider; import java.io.BufferedReader;import java.io.IOException;import java.io.I ...

  7. 1.求链表中的倒数第K个节点

    注意事项:1.要是K大于链表长度怎么办? 2.k<=0怎么办? ListNode* FindR_Kth(ListNode* p_head, unsigned int k) 2 {//找到链表的倒 ...

  8. Laravel5.5学习笔记

    安装composer 下载安装脚本 php -r "copy('https://install.phpcomposer.com/installer', 'composer-setup.php ...

  9. CH 5102Mobile Service题解

    题目: 用动态规划很容易将完成任务量作为dp的阶段,通过指派服务员,从当前i-1个任务转移到i个任务: 我们可以用一个四维数组f[i][x][y][z]来表示在完成当前任务i时,三个机器人分别在x,y ...

  10. luogu P4482 [BJWC2018] Border 的四种求法 - 后缀数组

    题目传送门 传送门 题目大意 区间border. 照着金策讲稿做. Code /** * luogu * Problem#P4482 * Accepted * Time: 8264ms * Memor ...