非常教程

React参考手册

高级指南 | Advanced Guides

Context

注意: React.PropTypes自从React v15.5以来,它已经进入了一个不同的包。请使用该prop-types库,而不是定义contextTypes。我们提供了一个codemod脚本来自动化转换。

通过React,可以轻松跟踪通过React组件的数据流。当你看一个组件时,你可以看到哪些道具被传递,这使得你的应用程序很容易推理。

在某些情况下,您希望通过组件树传递数据,而不必在每个级别手动传递道具。您可以直接在React中使用强大的“上下文”API执行此操作。

为什么不使用上下文

绝大多数应用程序不需要使用上下文。

如果你希望你的应用程序稳定,不要使用上下文。这是一个实验性的API,它很可能在未来的React版本中被打破。

如果您不熟悉像Redux或MobX这样的状态管理库,请不要使用上下文。对于许多实际应用来说,这些库和它们的React绑定对于管理与许多组件相关的状态是一个很好的选择。Redux很可能是解决问题的正确解决方案,而不是正确的解决方案。

如果您不是经验丰富的React开发人员,请不要使用上下文。通常只有使用道具和状态才能实现功能。

如果您坚持使用上下文而不管这些警告,请尝试将上下文的使用隔离到一个小区域,并尽可能避免直接使用上下文API,以便在API更改时更容易升级。

如何使用上下文

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

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道具来适当地设计ButtonMessage组件。使用上下文,我们可以自动将它传递给树:

import PropTypes from 'prop-types';

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

Button.contextTypes = {
  color: 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: PropTypes.string
};

通过添加childContextTypesgetChildContextMessageList(上下文提供),阵营传递的子树中向下自动信息和任何组分(在这种情况下,Button)可以通过定义访问它contextTypes

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

亲子合作

Context还可以让你建立一个父母和孩子交流的API。例如,以这种方式工作的一个库是React Router V4:

import { BrowserRouter as 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部分,每个LinkRoute可回传送到含有Router

在使用与此类似的API构建组件之前,请考虑是否有更清晰的替代方案。例如,如果您愿意,您可以将整个React组件作为道具传递。

在生命周期方法中引用上下文

如果contextTypes在组件内定义,则以下生命周期方法将收到附加参数,即context对象:

  • constructor(props, context)
  • componentWillReceiveProps(nextProps, nextContext)
  • shouldComponentUpdate(nextProps, nextState, nextContext)
  • componentWillUpdate(nextProps, nextState, nextContext)

注意:截至React 16,componentDidUpdate不再收到prevContext

在无状态功能组件中引用上下文

无状态的功能组件也可以引用,context如果contextTypes被定义为该功能的属性。以下代码显示了一个Button写入无状态功能组件的组件。

import PropTypes from 'prop-types';

const Button = ({children}, context) =>
  <button style={{background: context.color}}>
    {children}
  </button>;

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

更新上下文

不要这样做。

React有一个API来更新上下文,但它基本上被打破了,你不应该使用它。

getChildContext功能将在状态或道具改变时被调用。为了更新上下文中的数据,使用this.setState。触发本地状态更新。这将触发一个新的环境,并且变化将被孩子接收。

import PropTypes from 'prop-types';

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: PropTypes.string
};

的问题是,如果由组分变化,即使用该值后代提供上下文值将不会如果中间父返回更新falseshouldComponentUpdate。这完全无法控制使用上下文的组件,所以基本上无法可靠地更新上下文。这篇博文很好地解释了为什么这是一个问题,以及如何解决这个问题。

React

React 起源于 Facebook 的内部项目,主要用于构建UI。你可以在React里传递多种类型的参数,如声明代码,帮助你渲染出UI、也可以是静态的HTML DOM元素、也可以传递动态变量、甚至是可交互的应用组件。

主页 https://reactjs.org/
源码 https://github.com/facebook/react
发布版本 16.1.0