preface

Why not use Redux

In a nutshell, Redux is too cumbersome to use:

  • More suitable for medium and large projects
  • The process of adding a global state is cumbersome and error-prone
  • whenReduxAs the state tree grows, maintenance becomes more difficult

React Hook find out

Since React Hook was released, people have come up with the idea of using useContext and useReducer to simulate Redux

What are the benefits:

  • You can andReduxFor separate use, you only need to add state where it is used, which is equivalent to a local global state.
  • Ideal for small projects or individual studyReactThe development of
  • Don’t write too much code, easy follow-up maintenance

UseContext and useReducer

useContext

So before we use useContext, we need to know what Context is, and it’s in the documentation, right

Context is designed to share data that is “global” to a component tree, such as the currently authenticated user, topic, or preferred language.

In other words, it is best to use Context to manage our “global” state.

UseContext is there to receive the context object and return the value of the context. In plain English, we can access the global state Context through useContext.

useReducer

Let’s look at the useReducer functions first.

const [state, dispatch] = useReducer(reducer, initialArg, init);
Copy the code

It receives a Reducer like (state, action) => newState and returns the current state and the expected accompanying Dispath method. (You’ll be familiar with Redux) official documentation

Began to practice

Let’s use a simple example to implement Redux using useContext and useReducer.

This example uses an implementation theme color switch to manage global state

Initialize the project

You can create a React project to test using create-react-app or simulate it in CodeSandbox

I write my projects in TypeScript, and you can do the same

NPX create-react-app my-app --typescript# orYarn create react-app my-app --typescriptCopy the code

Create a TypeScript React project

Create two child components

After the project is created, create a new Pages in the SRC directory

Pages creates two components, switch and Theme, respectively. Only the main directory structure is listed here

. ├ ─ ─ the SRC | └ ─ ─ pages | | ├ ─ ─ the switch | | | └ ─ ─ index. The TSX / / used to modify the theme state | | └ ─ ─ the state | | | └ ─ ─ index. The TSX / / is used for displaying the theme └─ store ├ ─ theme. TSX // use to store theme stateCopy the code

Create the State component (to display the theme State)

index.tsx

import React from 'react'

const State: React.FC = () => {
    return(<div> let me show the global variable </div>)}export default State;
Copy the code

Create the Switch component (to change the theme state)

index.tsx

import React from 'react'

const Switch: React.FC = () => {
    return</button> </button> </button>export default Switch;
Copy the code

Now let’s introduce both components into app.tsx

import React from 'react';
import Switch from './pages/switch'
import State from './pages/state'
import './App.css';

const App: React.FC = () => {
  return (
    <div className="App">
      <Switch></Switch>
      <State></State>
    </div>
  );
}

export default App;
Copy the code

Now when we run our project, we can see that the page looks something like this

Now we’re done with the first step

State management

Create a store directory file in the SRC directory and create a new file named theme.tsx

theme.tsx

Initialize the topic value

import React, { createContext, Context } from 'react'ITheme {theme: string} // Initializationexport const initialTheme: ITheme = {
    theme: 'Waiting to change subject'} // Create a Context instanceexportconst ThemeContext: Context<any> = createContext(initialTheme); /** * Create a Theme component * All children of the Theme component wrap can be accessed to value */ by calling ThemeContextexport const Theme: React.FC = (props) => {
    return (
        <ThemeContext.Provider value={{state: initialTheme}}>
            {props.children}
        </ThemeContext.Provider>
    )
}
Copy the code

An important point here is that when the value of themecontext.provider changes, all of its internal child components are rerendered.

So we need to wrap the Theme component around State and Switch

At this point app.tsx becomes

import React from 'react';
import Switch from './pages/switch'
import State from './pages/state'
import { Theme } from './store/theme'
import './App.css';

const App: React.FC = () => {
  return (
    <div className="App">
      <Theme>
        <Switch></Switch>
        <State></State>
      </Theme>
    </div>
  );
}

export default App;
Copy the code

Now we’re done with step 2

State Read State (useContext)

We can now read the State of the Theme from useContext within the State component

UseContext import React, {useContext} from'react'// Introduce the ThemeContext import {ThemeContext} from'.. /.. /store/theme'Const State: react. FC = () => {// Get the Theme value const {State} = useContext(ThemeContext)return (
        <div className="theme light">{state.theme}</div>
    )
}

export default State;
Copy the code

Run our project now and see that State has read the value of Theme, indicating that our third step has been successful

Changing state (useReducer)

Next we need to change the Theme value using the two buttons in the Switch to see if the State in the State component has changed

Add reducer in the Theme

Use the useReducer in the Theme component and add the Reducer method to modify the Theme state

import React, { createContext, Context, useReducer } from 'react'ITheme {theme: string} // Initializationexport const initialTheme: ITheme = {
    theme: 'Waiting to change subject'} // Create a Context instanceexportconst ThemeContext: Context<any> = createContext(initialTheme); // (Added) Initialize store type, initialize value, reducerexport const CHANGE_THEME: string = 'CHANGE_THEME'; // (added) Compile the reducer functionexport const reducer = (state: ITheme, action: any) => {
    switch (action.type) {
        case CHANGE_THEME:
            return{... state, theme: action.theme } default: throw new Error(); }} /** * Create a Theme component * All children of the Theme component wrap can be accessed to value */ by calling ThemeContextexportConst Theme: react. FC = (props) => {// Update state by using useReducer const [state, dispatch] = useReducer(Reducer, Theme);return (
        <ThemeContext.Provider value={{state, dispatch}}>
            {props.children}
        </ThemeContext.Provider>
    )
}
Copy the code

At this point our Theme component is all written.

Switch Add event

The Switch also reads the state of the Theme via useContext and then adds a state-changing Dispatch to the button to change the state of the Theme

The modified Swtich component

import React, { useContext } from 'react'
import { ThemeContext, CHANGE_THEME } from '.. /.. /store/theme'Const Switch: react. FC = () => {// call dispatch to change the state const {dispatch} = useContext(ThemeContext)return (
        <section>
            <button 
                onClick={() => {
                    dispatch({ type: CHANGE_THEME, theme: "Change One"}); </button> <button onClick={() => {dispatch({);type: CHANGE_THEME, theme: "Change Two"}); </button> </section>)}export default Switch;
Copy the code

The effect of running the project is as follows

At this point, all steps are complete.

The demo has been uploaded to GitHub and can be compared with your code 😜

At the end

The original intention of writing this article is to feel that it is too much trouble to use Redux in React. With React Hook, there are fewer repetitive operations. I hope I can share with you. Remember to give me a thumbs-up oh, is a kind of encouragement to me, ha ha!

Other articles

How to change text color dynamically according to background color