[React Advanced Series] React Context Case Study: Updating the State of the Parent Component in the Child Component

[React Advanced Series] React Context Case Study: Updating the State of the Parent Component in the Child Component

I have always known that React Context is the method for implementing state management inside React, and I simply followed the official case to tap the rendering using Context, but it is always because the implementation of the method of updating the parent component of the parent component in the child component is too troublesome, and finally Still decided to use Redux - after all, although Redux's internal implementation relies on Context, it is already encapsulated. However, I still want to learn about React in depth recently, including its state management mechanism. I just learned a very clean way of writing, so I wrote a note.

Basic Context and useContext hook usage

The basic implementation page is as follows:

context theme

There are two files that have been changed:

  • App.js

    The main thing is to clean up the page, make the rendered content simpler, and add a subcomponent:

    import {
          
           useTheme } from "./context";
    import "./styles.css";
    
    const Child = () => {
          
          
      const themeContext = useTheme();
    
      return <div style={
          
          themeContext}> "Theme" </div>;
    };
    
    export default function App() {
          
          
      return (
        <div className="App">
          <Child />
        </div>
      );
    }
    
  • context.js

    This is the main implementation part, themeContextand simply encapsulates , so that other components do not need to mechanically use useContext(ThemeContext)such code every time. The implementation is as follows:

    import React, {
          
           useContext } from "react";
    
    const theme = {
          
          
      dark: {
          
          
        backgroundColor: "#333",
        color: "#ccc",
        padding: "2em",
        margin: "2em",
      },
      light: {
          
          
        backgroundColor: "#ccc",
        color: "#333",
        padding: "2em",
        margin: "2em",
      },
    };
    
    const ThemeContext = React.createContext(theme.dark);
    
    export const useTheme = () => useContext(ThemeContext);
    

Of course, this is a relatively lazy approach. Instead of using <ThemeContext.Provider value={state}> ... </ThemeContext.Provider>the method to pass values, it is directly written to death when it is created.

The next step will be the secondary encapsulation of Context, the realization Provierof the part.

Secondary encapsulation of Context

Here, a custom hook is used to encapsulate the Context, and themethe value of is stored in the state of the custom hook, so setStatethat the value in the Context can be updated later by using the method.

The updates are as follows:

  • App.js

    Only a pair ThemeContextProviderof .

    It should be noted that, because the sub-component is ThemeContextProviderwrapped the App, the value of ThemeContext cannot be obtained in the App, and only the sub-component "inherits" the content in the Context.

    export default function App() {
          
          
    return (
    <ThemeContextProvider>
      <div className="App">
        <Child />
      </div>
    </ThemeContextProvider>
    );
    
  • context.js

    import React, {
          
           useContext, useState } from "react";
    
    // 因为变量名冲突的关系,这里将其改成了大写……不过常量大写也比较正常
    const THEME = {
          
          
      dark: {
          
          
        backgroundColor: "#333",
        color: "#ccc",
        padding: "2em",
        margin: "2em",
      },
      light: {
          
          
        backgroundColor: "#ccc",
        color: "#333",
        padding: "2em",
        margin: "2em",
      },
    };
    
    const ThemeContext = React.createContext();
    
    export const useTheme = () => useContext(ThemeContext);
    
    export const ThemeContextProvider = ({
           
            children }) => {
          
          
      const [theme, setTheme] = useState(THEME.dark);
    
      return (
        <ThemeContext.Provider value={
          
          theme}>{
          
          children}</ThemeContext.Provider>
      );
    };
    

    All we have to do after that is to pass setThemethis method to the child component.

    Given that Context can only pass one value, the method taken here is to create a new Context again, whose value is to update the set function in the cuttom hook.

Added Update Context

This step is equivalent to encapsulating the Context three times. The specific changes are as follows:

// 之前的THEME没有变化

const ThemeContext = React.createContext();
const ThemeUpdateContext = React.createContext();

export const useTheme = () => useContext(ThemeContext);
export const useThemeUpdate = () => useContext(ThemeUpdateContext);

export const ThemeContextProvider = ({
     
      children }) => {
    
    
  const [theme, setTheme] = useState(THEME.dark);

  const updateTheme = ({
     
      theme }) => {
    
    
    // 这里只是做一个传值的示范
    console.log(theme);

    setTheme((prevTheme) =>
      prevTheme === THEME.dark ? THEME.light : THEME.dark
    );
  };

  return (
    <ThemeContext.Provider value={
    
    theme}>
      <ThemeUpdateContext.Provider value={
    
    updateTheme}>
        {
    
    children}
      </ThemeUpdateContext.Provider>
    </ThemeContext.Provider>
  );
};

Use useThemeUpdate to change the state of the Context

The update in App.js is as follows:

const Child = () => {
    
    
  const themeContext = useTheme();
  const updateTheme = useThemeUpdate();

  return (
    <div
      style={
    
    themeContext}
      onClick={
    
    () => updateTheme({
    
     theme: "hello world" })}
    >
      "Theme"
    </div>
  );
};

It can be seen that the update logic is relatively clear, and the final implementation effect is as follows:

context complete

From this point of view, if the project structure is relatively simple and the demand for Redux-Saga is not very large, it may be a good choice to use Context hook directly. After all, hooks save the complicated process of Context.Consumerusing callback functions to obtain values. . After encapsulating the Context three times, you can directly use const someVar = useXXX();the method to obtain the value, and const updateSomeVar = useXXXUpdate();the method to update it will not be too complicated.

Finally, if you want to save a layer of wrapper, you can also use this method:

<ThemeContext.Provider value={
    
    {
    
     theme, updateTheme }}>
  {
    
    children}
</ThemeContext.Provider value={
    
    {
    
     theme, updateTheme }}>

// when you need to use it
const {
    
    theme, updateTheme } = useTheme();

However, this is also a personal tendency, and I don't care about the details of typo and automatic import prompts. After all, most of the time I still think that it is more convenient to have automatic prompts/automatic import.

Guess you like

Origin blog.csdn.net/weixin_42938619/article/details/124122194