React Context 常规使用方式

118 阅读2分钟

Context 基本使用

Context 设计目的是为了共享那些对于一个组件树而言是“全局”的数据,例如当前认证的用户、主题或首选语言。

import React from "react";
// 创建一个ThemeContext
const ThemeContext = React.createContext("light");
class App extends React.Component {
  state = { theme: "dark" };
  render() {
    return (
      // 包裹消费组件,并提供value
      <ThemeContext.Provider value={this.state.theme}>
        <Toolbar />
      </ThemeContext.Provider>
    );
  }
}

function Toolbar() {
  return (
    <div>
      <ThemedButton />
    </div>
  );
}
class ThemedButton extends React.Component {
  // 使用静态contexType属性去接ThemeContext,然后这个组建中都可以使用this.context,他的是就是 <ThemeContext.Provider value="dark">中的value
  static contextType = ThemeContext;
  render() {
    return <div>{this.context}</div>;
  }
}

export default App;


什么时候使用Context

一些全局状态需要在子孙组件中使用,这时候我们将考虑Context。我们先不使用redux等状态管理库,比如我们自己封装组建是不考虑这些外部库的。但是很多情况我们是不需要使用Context也可以达到一样的目的。我改改上面的例子如下:

import React from "react";

class App extends React.Component {
  state = { theme: "dark" };
  render() {
    const themeButton = <ThemedButton theme={this.state.theme} />;
    return <Toolbar themeButton={themeButton} />;
  }
}

function Toolbar(props) {
  return (
    <div>
      {/* <ThemedButton /> */}
      {props.themeButton}
    </div>
  );
}
function ThemedButton(props) {
  return <div>{props.theme}</div>;
}

export default App;

Context API

Cntext.displayName

const ThemeContext = React.createContext("light");
ThemeContext.displayName = 'MyThemeContext'

context 对象接受一个名为 displayName 的 property,类型为字符串。React DevTools 使用该字符串来确定 context 要显示的内容。

截屏2022-04-08 上午9.02.59.png

Context.Consumer

我们改写第一部分的ThemedButton如下

const ThemedButton = ()=> {
  // 这里不使用static contextType = ThemeContext
  // 我们用 <ThemeContext.Consumer>{value=>{}}</ThemeContext.Consumer>

    return <ThemeContext.Consumer>{value=><div>{value}</div>}</ThemeContext.Consumer>
}

这里使用函数组件去消费context

截屏2022-04-08 上午9.15.29.png

如何在嵌套组件中直接更新context

我们继续改写上面的例子

import React from "react";
// 创建一个ThemeContext
const ThemeContext = React.createContext("light");
ThemeContext.displayName = "MyThemeContext";
class App extends React.Component {

  changeTheme = (theme) => {
    this.setState({ theme });
  };
  state = { theme: "dark", changeTheme: this.changeTheme };

  render() {
    return (
      // 包裹消费组件,并提供value
      <ThemeContext.Provider value={this.state}>
        <Toolbar />
      </ThemeContext.Provider>
    );
  }
}

function Toolbar() {
  return (
    <div className="tool-bal">
      <ThemedButton />
    </div>
  );
}
const ThemedButton = () => {
  // 这里不使用static contextType = ThemeContext
  // 我们用 <ThemeContext.Consumer>{value=>{}}</ThemeContext.Consumer>

  return <ThemeContext.Consumer>{({theme, changeTheme}) => <div onClick={()=>{changeTheme('pure')}}>{theme}</div>}</ThemeContext.Consumer>;
};

export default App;

其实就是context里面可以提供函数。

如何消费多个Context

import React from "react";
const admin = { user: "admin" };
// 创建一个ThemeContext
const ThemeContext = React.createContext("light");
const UserContext = React.createContext(admin);
ThemeContext.displayName = "MyThemeContext";
UserContext.displayName = "MyUserContext";
class App extends React.Component {
  changeTheme = (theme) => {
    this.setState({ theme: { theme } });
  };
  state = {
    theme: { theme: "dark", changeTheme: this.changeTheme },
    user: "gavin",
  };

  render() {
    return (
      // 包裹消费组件,并提供value
      <ThemeContext.Provider value={this.state.theme}>
        <UserContext.Provider value={this.state.user}>
          <Toolbar />
        </UserContext.Provider>
      </ThemeContext.Provider>
    );
  }
}

function Toolbar() {
  return (
    <div className="tool-bal">
      <ThemedButton />
    </div>
  );
}
const ThemedButton = () => {
  // 这里不使用static contextType = ThemeContext
  // 我们用 <ThemeContext.Consumer>{value=>{}}</ThemeContext.Consumer>

  return (
    <ThemeContext.Consumer>
      {({ theme, changeTheme }) => (
        <UserContext.Consumer>
          {(user) => (
            <div
              onClick={() => {
                changeTheme("pure");
              }}
            >
              {theme}-{user}
            </div>
          )}
        </UserContext.Consumer>
      )}
    </ThemeContext.Consumer>
  );
};

export default App;

使用Context要注意的事

Context.Provider value属性事浅比较,不要使用字面量。应该是value={this.state}

value={{something: 'something'}} ❌
value={this.state.value} ✔️