Introduction: Refer to the React Chinese document for notes

What is Context?

In react applications, data is always passed top-down through props. This can be extremely cumbersome for certain types of attributes (e.g. locale preferences, UI themes). Context can share data that is “global” to a component tree. This eliminates the need to explicitly pass props layer by layer through the component tree

class App extends React.Component {
  render() {
    return <Toolbar theme="dark" />; }}/ / pass prop
function Toolbar(props) {
  return (
    <div>
      <ThemedButton theme={props.theme} />
    </div>
  );
}
// Pass prop
class ThemedButton extends React.Component {
  render() {
    return <Button theme={this.props.theme} />; }}Copy the code

Using context avoids passing props through intermediate elements

//1. Create a context for theme. The default value is light
const ThemeContext = React.createContext('light');

class App extends React.Component {
  render() {
    return (
      // 2. Use Provider to pass the theme. Here, pass on the dark
      <ThemeContext.Provider value="dark">
        <Toolbar />
      </ThemeContext.Provider>); }}/ /! Intermediate components need not be specified
function Toolbar() {
  return (
    <div>
      <ThemedButton />
    </div>
  );
}

class ThemedButton extends React.Component {
  // 3. Specify contextType to read the theme context object.
  static contextType = ThemeContext;
  // 4.React finds the nearest Provider and uses this.context to read the Provider's value.
  render() {
    return <Button theme={this.context} />; }}Copy the code

Context is mainly used when many components at different levels need to access the same data. Use with caution, as this makes components less reusable

API

React.createContext

Create a Context object:

const MyContext = React.createContext(defaultValue);
Copy the code

Context.Provider

The Context object returns a Provider React component:

<MyContext.Provider value={some value}/>
Copy the code
  • The Provider receives a value property and passes it to the consumer component (the component inside the Provider React component).
  • When the value of the Provider changes, all of its internal consuming components are re-rendered
  • When the consuming component does not match the Provider, the Context object’s defaultValue parameter takes effect.
  • A Provider can be associated with multiple consumer components. Multiple providers can also be nested, with the inner layer overwriting the data in the outer layer

Class.contextType

If the public Class Fields syntax is used, the contextType can be initialized static. ContextType specifies the Context object to read:

class MyClass extends React.Component {
  static contextType = MyContext;
  render() {
    let value = this.context; }}Copy the code

The more common is class.contextType. Class. ContextType Reassigns to Context:

class MyClass extends React.Component {
 / /...
  render() {
    let value = this.context; }}/ / assignment
MyClass.contextType = MyContext;
Copy the code

The contextType mounted on the class will be reassigned to a Context object created by react.createcontext (). Allows you to use this.context to access the most recent context value. It can be accessed in any lifecycle

Context.Consumer

Render the React node based on the context value

<MyContext.Consumer>
  {value= > /* Render based on context value */}
</MyContext.Consumer>
Copy the code

This requires the practice of function as a child. The React function takes the context value and returns a React node. The value passed to the function is the value provided by the Provider closest to the context.

Context.displayName

Change the name of the context object displayed in React DevTools

const MyContext = React.createContext(/* some value */);
MyContext.displayName = 'MyDisplayName';

<MyContext.Provider> // DevTools will display "myDisplayName.provider"
Copy the code

Example 01- Dynamic Context

Theme-context. js: stores the themes and theme context objects

//1. Declare a Themes object to store the theme export
export const themes = {
    light: {
      background: 'orange',},dark: {
      background: '#eee',}};//2. Create the context object export
export const ThemeContext = React.createContext(
    themes.dark     //2. Set the default value dark
);
Copy the code

Themed Button.js: Creating a Themed button widget (ThemedButton)

//1. Introduce the theme context object
import {ThemeContext} from './theme-context';

class ThemedButton extends Component {
  render() {
    let props = this.props;
    return (
      <button
        {. props}
        style={{backgroundColor: this.context.background/ /}}3.Read the values / >); }}//2. Context is reassigned
ThemedButton.contextType = ThemeContext;

//4. Export button components
export default ThemedButton;
Copy the code

App.js

//1. Introduce the context object and themes object
import {ThemeContext, themes} from './theme-context';
//2. Introduce the button component
import ThemedButton from './themed-button';

// The middle component puts buttons to switch themes
function Toolbar(props) {
  return (
    <ThemedButton onClick={props.changeTheme}>
      Change Theme
    </ThemedButton>
  );
}

/ / the parent component
class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      theme: themes.light,
    };

    //3. Define the event to switch the theme
    this.toggleTheme = () = > {
      this.setState(state= > ({
        theme:state.theme === themes.dark? themes.light:themes.dark,
      }));
    };
  }

  render() {
    return (
      <div>{/* 4. Assign the value of the Context object's Provider */}<ThemeContext.Provider value={this.state.theme}>{/* 5.prop assign incoming event */}<Toolbar changeTheme={this.toggleTheme} />
        </ThemeContext.Provider>}}}}}}}}}}}}}}}}}}}}}}<div>
          <Toolbar />
        </div>
      </div>); }}export default App
Copy the code

Example 02- Updating the Context in a nested component

Pass a function through the context that causes the consuming component to update the context itself (scenario: update the context in a deeply nested component) :

theme-context.js

export const ThemeContext = React.createContext({
  theme: themes.dark,
  toggleTheme: () = >{}});Copy the code

theme-toggler-button.js

import {ThemeContext} from './theme-context';

// The button component not only gets the theme value, but also a toggleTheme function from the context
function ThemeTogglerButton() {
  return (
    // context. Consumer: Render the React node based on the Context value
    <ThemeContext.Consumer>
      {({theme, toggleTheme}) => (
        <button onClick={toggleTheme}
          style={{backgroundColor: theme.background}} >
          Toggle Theme
        </button>
      )}
    </ThemeContext.Consumer>
  );
}
export default ThemeTogglerButton;
Copy the code

App.js

import {ThemeContext, themes} from './theme-context';
import ThemeTogglerButton from './theme-toggler-button';

class App extends Component {
  constructor(props) {
    super(props);
    //1. Define events
    this.toggleTheme = () = > {
      this.setState(state= > ({
        theme:state.theme === themes.dark? themes.light:themes.dark,
      }));
    };
    / / 2. Define the state
    this.state = {
        theme: themes.light,
        toggleTheme: this.toggleTheme,
      };
  }
  render() {
    // 3. Assign a value to the Provider that contains the current topic and event
    return (
      <ThemeContext.Provider value={this.state}>
        <ThemeTogglerButton />
      </ThemeContext.Provider>); }}Copy the code

Example 03- Consuming multiple contexts

To ensure that the context is quickly rerendered, React needs to make each consuming component’s context a separate node in the component tree.

App.js

import ProfilePage from './ProfilePage'

// 1. Create the theme context
const ThemeContext = React.createContext({
  bgColor:'#eee'.fontColor:'balck'
});
// 2. Create user context
const UserContext = React.createContext({
  name: 'Guest'});class App extends Component {
  constructor(props){
    super(props)
    //3. Set the desired state of the app component
    this.state = {
      theme: {
        bgColor:'orange'.fontColor:'white'
      },
      user: {
        name:'Jack'}}; }render() {
    const {theme,user}=this.state
    //4. Pass the value to the Provider
    return (
      <ThemeContext.Provider value={theme}>
        <UserContext.Provider value={user}>
            <Content />
        </UserContext.Provider>
      </ThemeContext.Provider>); }}function Content() {
  //5. You can now access the theme and user passed by the Provider
  return (
    <ThemeContext.Consumer>
      {theme => (
        <UserContext.Consumer>
          {user => (
            <ProfilePage user={user} theme={theme} />
          )}
        </UserContext.Consumer>
      )}
    </ThemeContext.Consumer>
  );
}

export default App
Copy the code

ProfilePage.js

export default function ProfilePage (props){
    const {user,theme}=props
    return(
        // Pass an object to style
        <div style={{display:'inline-block',padding:'5px 8px',backgroundColor:theme.bgColor.color:theme.fontColor}} >
            {user.name}
        </div>)}Copy the code

Sample source code is available in branches 10, 11, and 12