react进阶---Context

370 阅读2分钟

组件跨层级通信 - Context

一.概念

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

二.API

  1. React.createContext
const MyContext = React.createContext(defaultValue);
  1. Context.Provider
<MyContext.Provider value={/* 某个值 */}>
  1. Class.contextType(只能用在类组件上,只能订阅单一contextType)
class MyClass extends React.Component {
  static contextType = MyContext;
  render() {
    let value = this.context;
    /* 基于这个值进行渲染工作 */
  }
}
  1. Context.Consumer
<MyContext.Consumer>
  {value => /* 基于 context 值进行渲染*/}
</MyContext.Consumer>
  1. useContext(hook方法,只能用在function组件当中,或者自定义hook中)

三.实际项目中的使用

  1. 新建一个文件---src/Contenxt.js,用于定义createContext,Provider,Consumer
import React from "react";

export const ThemeContext = React.createContext({themeColor: "pink"});
export const ThemeProvider = ThemeContext.Provider;
export const ThemeConsumer = ThemeContext.Consumer;

export const UserContext = React.createContext();
export const UserProvider = UserContext.Provider;
export const UserConsumer = UserContext.Consumer;

  1. 在页面引入---src/pages/ContextPage.js,并提供value
import React, {Component} from "react";
import {ThemeProvider, UserProvider, UserContext} from "../Context";
import ConsumerPage from "./ConsumerPage";
import UseContextPage from "./UseContextPage";

export default class ContextPage extends Component {
  constructor(props) {
    super(props);
    this.state = {
      theme: {
        themeColor: "red"
      },
      user: {name: "曾小白"}
    };
  }
  render() {
    const {theme, user} = this.state;
    return (
      <div>
        <h3>ContextPage</h3>
        <ThemeProvider value={theme}>
          <UserProvider value={user}>
            <ConsumerPage />
            <UseContextPage />
          </UserProvider>
        </ThemeProvider>
      </div>
    );
  }
}

  1. 在页面中接收---src/pages/ConsumerPage.js,接收value
import React, {Component} from "react";
import {ThemeConsumer, UserConsumer} from "../Context";

export default class ConsumerPage extends Component {
  render() {
    return (
      <div>
        <h3>ConsumerPage</h3>
        <ThemeConsumer>
          {themeContext => (
            <div className={themeContext.themeColor}>
              omg
              <UserConsumer>
                {userContext => <Child {...userContext} />}
              </UserConsumer>
            </div>
          )}
        </ThemeConsumer>
      </div>
    );
  }
}

function Child(props) {
  return <div>{props.name}</div>;
}

  1. 在function中使用---src/pages/UseContextPage.js,使用useContext
import React, {useContext} from "react";
import {ThemeContext, UserContext} from "../Context";

export default function UseContextPage(props) {
  const {themeColor} = useContext(ThemeContext);
  const {name} = useContext(UserContext);

  return (
    <div className="border">
      <h3 className={themeColor}>UseContextPage</h3>
      <p>{name}</p>
    </div>
  );
}

注意

当 provider 的父组件进行重渲染时,可能会在 consumers 组件中触发意外的渲染 举个栗子,当每一次 Provider 重渲染时,以下的代码会重渲染所有下面的 consumers 组件,因为 value 属性总是被赋值 为新的对象:

class App extends React.Component {
  render() {
    return (
      <Provider value={{something: 'something'}}>
        <Toolbar />
      </Provider>
); }
}

为了防止这种情况,将 value 状态提升到父节点的 state 里

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: {something: 'something'},
    };
  }
  render() {
    return (
      <Provider value={this.state.value}>
        <Toolbar />
      </Provider>
    ); 
  }
}

总结

  1. 后面我们要学习到的react-redux的 ,就是通过 Context提供一个全局态的 store ,
  2. 路由组件react-router通过 Context 管理路由状态等等。