Redux is undoubtedly the preferred state management solution for many React projects, but I find it a poor development experience.

For example, if you are developing a very complex feature and need to add global state continuously, you have to repeat the following steps each time you add:

  1. Go to the folder that manages Redux, think about where to put the state in the state tree, and create a new folder and name itmyFeature.
  2. Create three filesmy-feature/actions.jsmy-feature/reducer.js,my-feature/type.js
  3. CombineReducer and reduce
  4. Introduce action into the component
  5. Connect to your component via Connect HOC
  6. Add two methods mapStateToProps and mapDispatchToProps

This is just a state, but writing too much template code is secondary, and the worst thing is that it interrupts your thinking.

Also, as the project gets larger, redux’s state tree gets larger and more difficult to maintain.

How does useContext + useReducer replace redux?

UseContext and useReducer are new apis introduced in React 16.8.

UseContext: Provides access to global state, avoiding layers of state passing.

UseReducer: Redux is used to update the status of complex logic.

Here is a simple example of how useContext + useReducer replaces Redux.

The code has been placed in the CodesandBox to view the complete code

This example has only one function, click the button to change the font color.

start

First create a project with create-react-app. You can also create a React app on CodeSandbox.

Create the color display component ShowArea

import React from 'react'

const ShowArea = (props) = > {
  return (
    <div style={{color: "blue}} ">The font color is displayed as blue</div>)}export default ShowArea
Copy the code

Create the button component buttons

import React from "react";

const Buttons = props= > {
  return (
    <React.Fragment>
      <button>red</button>
      <button>yellow</button>
    </React.Fragment>
  );
};

export default Buttons;
Copy the code

Import ShowArea and Buttons into index.js

import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";

import ShowArea from './ShowArea'
import Buttons from './Buttons'

function App() {
  return (
    <div className="App">
      <ShowArea />
      <Button />
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Copy the code

State management

It was obvious that the ShowArea component needed a color state, so we created color.js to handle the state.

// color.js
import React, { createContext } from "react";

/ / create the context
export const ColorContext = createContext({});

/** * Create a Color component * all child components wrapped by the Color component can be accessed by calling ColorContext to value */
export const Color = props= > {
  return (
    <ColorContext.Provider value={{ color: "blue}} ">
      {props.children}
    </ColorContext.Provider>
  );
};
Copy the code

The introduction of state

Modify index.js so that all child components have access to the color.

// index.js· · · · · · · · ·import { Color } from "./color";

function App() {
  return (
    <div className="App">
      <Color>
        <ShowArea />
        <Buttons />
      </Color>
    </div>); } · · · · · · · · ·Copy the code

To obtain state

Get the color in the ShowArea component

// ShowArea.js· · · · · · · · ·import { ColorContext } from "./color";

const ShowArea = props= > {
  const { color } = useContext(ColorContext);
  return <div style={{ color: color}} >Font color display is {color}</div>; }; · · · · · · · · ·Copy the code

Create the reducer

Add reducer to color.js to handle the logic for color updates.

import React, { createContext, useReducer } from "react";

/ / create the context
export const ColorContext = createContext({});

// reducer
export const UPDATE_COLOR = "UPDATE_COLOR"
const reducer = (state, action) = > {
  switch(action.type) {
    case UPDATE_COLOR:
      return action.color
    default:
      return state  
  }
}

/** * Create a Color component * Color component wrap all components have access to value */
export const Color = props= > {
  const [color, dispatch] = useReducer(reducer, 'blue')
  return (
    <ColorContext.Provider value={{color, dispatch}} >
      {props.children}
    </ColorContext.Provider>
  );
};
Copy the code

Update the status

Add a click event to the button and call Dispatch to update the color.

// buttons.js

import React, { useContext } from "react";
import { colorContext, UPDATE_COLOR } from "./color";

const Buttons = props= > {
  const { dispatch } = useContext(colorContext);
  return (
    <React.Fragment>
      <button
        onClick={()= >{ dispatch({ type: UPDATE_COLOR, color: "red" }); }} > red</button>
      <button
        onClick={()= >{ dispatch({ type: UPDATE_COLOR, color: "yellow" }); }} > yellow</button>
    </React.Fragment>
  );
};

export default Buttons;

Copy the code

conclusion

  • UseContext creates global state instead of passing state layer by layer.
  • UseReducer Creates a Reducer to update state based on different dispatchers.
  • State is added wherever the code is written, without breaking the thread and jumping into redux.
  • Global state separation prevents the Redux state tree from becoming unmanageable as the project grows.

Therefore, useContext + useReducer can completely replace React for state management. However, most React projects still use Redux, so it’s important to learn more about Redux.

reference

  • React Context vs Redux – Who wins?
  • React Context API simple tutorial. Does it replace Redux? + useContext, useReducer hooks
  • Provide more ways to bail out inside Hooks
  • Preventing rerenders with React.memo and useContext hook
  • Don ‘t use Redux!