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. Asp.Net Core WebApi 和Asp.Net WebApi上传文件

    public class UpLoadController : ControllerBase { private readonly IHostingEnvironment _hostingEnviro ...

  2. c++常用

    常用函数,方便查找,不定时更新. 1. 生成随机数 #include <iostream> #include <stdlib.h> #include <time.h> ...

  3. Cannot locate BeanDefinitionParser for element [scoped-proxy]

    指定使用 CGLIB 而不使用 JDK 生成代理对象:注意:此两个标签必须同时出现,不然会报:Cannot locate BeanDefinitionParser for element [scope ...

  4. Python中__init__()和self的有啥用

    这篇博客让我一下子就理解了,https://www.cnblogs.com/illusion1010/p/9527034.html,感谢博主 由于类可以起到模板的作用,因此,可以在创建实例的时候,把一 ...

  5. python zip()函数

    描述 zip() 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表. 如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同,利用 * 号操作符 ...

  6. SQL 连接(内连接,外连接)

    内连接 现在有两张表,学生表student1,成绩表SC1,两张表的数据如下 现在要对两张表做连接查询,连接一般需要写条件,where 或者 on 后面 , select * from student ...

  7. 最新QT4.8+kernel_3.2.5+uboot_2010.06+tslib移植成功-问题小结

    2012-02-19 21:34:13 都是从源码下载然后自己修改,使用与TQ2440,之前uboot其实已经完成了.但是yaffs2没带起来.现在回头看来是很简单的了.bootargs参数中我设置成 ...

  8. 五一培训 DAY1

    DAY1 枚举 例题1 题解: 例题2 题解: 例题3 题解: vis[ ]判断是否为素数,pri[ ]储存素数 例题4 题解: 例题5 题解: PS: i  <  1<<n    ...

  9. 对象序列化Serializable

    一.Java对象的存储 首先我们先来理解一下Java对象在内存中的存储! JVM的内存分为三个部分:栈(stack).堆栈(heap).方法区(method area): 栈:主要存储基本数据类型变量 ...

  10. office 2016 官方原版 (含Visio Project 等全套 )下载地址 (不含破解,非网盘下载)不用登录

    原文地址:https://www.heidoc.net/joomla/technology-science/microsoft/8-office-2016-direct-download-links ...