简介

Context 提供了一个无需为每层组件手动添加 props,就能在组件树间进行数据传递的方法。

老的Context

父组件定义getChildContext(){} 里面返回context对象,key-value对应
父组件定义childContextTypes 定义context的key的类型
子组件定义contextTypes 定义接收的context,使用this.context.key来获取context

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
};

新的Context

API

  • React.createContext & Context.Provider

    只有当组件所处的树中没有匹配到 Provider 时,其 defaultValue 参数才会生效。这有助于在不使用 Provider 包装组件的情况下对组件进行测试。注意:将 undefined 传递给 Provider 时,消费组件的 defaultValue 不会生效。

const MyContext = React.createContext(defaultValue);
<MyContext.Provider value={/* 某个值 */}>
  • Class.contextType

    挂载在 class 上的 contextType 属性会被重赋值为一个由 React.createContext() 创建的 Context 对象。这能让你使用 this.context 来消费最近 Context 上的那个值。你可以在任何生命周期中访问到它,包括 render 函数中。

    class MyClass extends React.Component {
    componentDidMount() {
     let value = this.context;
     /* 在组件挂载完成后,使用 MyContext 组件的值来执行一些有副作用的操作 */
    }
    componentDidUpdate() {
     let value = this.context;
     /* ... */
    }
    componentWillUnmount() {
     let value = this.context;
     /* ... */
    }
    render() {
     let value = this.context;
     /* 基于 MyContext 组件的值进行渲染 */
    }
    }
    MyClass.contextType = MyContext;
  • Context.Consumer
    <MyContext.Consumer>
    {value => /* 基于 context 值进行渲染*/}
    </MyContext.Consumer>

消费多个 Context

// Theme context,默认的 theme 是 “light” 值
const ThemeContext = React.createContext('light');

// 用户登录 context
const UserContext = React.createContext({
  name: 'Guest',
});

class App extends React.Component {
  render() {
    const {signedInUser, theme} = this.props;

    // 提供初始 context 值的 App 组件
    return (
      <ThemeContext.Provider value={theme}>
        <UserContext.Provider value={signedInUser}>
          <Layout />
        </UserContext.Provider>
      </ThemeContext.Provider>
    );
  }
}

function Layout() {
  return (
    <div>
      <Sidebar />
      <Content />
    </div>
  );
}

// 一个组件可能会消费多个 context
function Content() {
  return (
    <ThemeContext.Consumer>
      {theme => (
        <UserContext.Consumer>
          {user => (
            <ProfilePage user={user} theme={theme} />
          )}
        </UserContext.Consumer>
      )}
    </ThemeContext.Consumer>
  );
}