Redux is a predictable state container for JavaScript apps.

React Hook Redux state machine

The code for this article can be viewed in the CodeSandbox.

Redux is a data state manager (state machine) that is often used by React. It stores all data states in the store in the form of an object tree and changes the states by triggering actions.

Because Redux was not written just for React, React is often used with react-redux. React-redux uses two main apis called Providers and Connect to improve the efficiency and experience of Redux development.

Prior to React 16.8, the best way to implement a unified state machine was to use Redux. However, the useContext and useReducer additions to the React 16.8 Hook API allow us to implement our own state machine with Redux’s core functionality.

Let’s start by looking at what Redux’s three basic principles are:

  1. Single data source – The state of the entire application is stored in the object tree of a single store
  2. State is read-only – the only way to change state is to trigger an action
  3. Use pure functions to modify – To describe how Actions modify state, you need to write reducers

We follow these three basic principles to develop our own state machine. In fact, if you look at the use of useReducer, you can see that it already meets principles 2 and 3

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

Therefore, we compiled state and Reducer based on the examples on the official website.

The file directory is as follows:

public
src
  reducer
    index.js
  index.js
  style.css
package.json
Copy the code

Compile initialState and Reducer in the index.js file of the Reducer folder:

export const initialState = { count: 0 };

export function reducer(state, action) {
  switch (action.type) {
    case "increment":
      return { count: state.count + 1 };
    case "decrement":
      return { count: state.count - 1 };
    default:
      throw new Error();
  }
}
Copy the code

A store is then generated in SRC /index.js, and only one store is created in the top-level component to comply with principle 1.

import { reducer, initialState } from "./reducer";

const store = useReducer(reducer, initialState);
Copy the code

As you can see, it is very easy to apply useReducer to create a state machine that meets Redux’s three basic principles. Then we need to consider how to transfer store state to deeper components. In Redux we use the subscribe method to subscribe to the state, whereas with react-Redux we can pass the store to the sub-components like props, so we don’t have to subscribe every time. So, next we use the React Context API to implement state transfer.

Create an AppContext in SRC /index.js with an empty initial value:

const AppContext = createContext({});
const { Provider } = AppContext;
Copy the code

Then use it in the top-level component App:

function App() {
  const store = useReducer(reducer, initialState);

  return (
    <Provider value={store}>
      <div className="App">
        <TopNavBar />
      </div>
    </Provider>
  );
}
Copy the code

This allows components, no matter how deep, to get the state of the data stored in the Store, and to get the Dispatch method to change the state. UseContext receives a context object (the return value of React. CreateContext) and returns the current value of that context.

function TopNavBar() {
  const value = useContext(AppContext);
  const [state] = value; // Where value is the store created by useReducer
  const { count } = state;

  return (
    <>
      <p>{count}</p>
      <Button />
    </>
  );
}
Copy the code

Use useContext in the Button component to get the dispatch and change the count value by firing an action:

function Button() {
  const value = useContext(AppContext);
  const [state, dispatch] = value;

  return (
    <div className="button-wrapper">
      <button type="button" onClick={()= > dispatch({ type: "increment" })}>
        Plus
      </button>
      <button type="button" onClick={()= > dispatch({ type: "decrement" })}>
        Minus
      </button>
    </div>
  );
}
Copy the code

A compact version of the state machine that meets the three principles of Redux and has some of the functionality of React-Redux is complete. Some applications that don’t need to manage too much complex state can use this approach to create their own state machines. Of course, there are other features like Effect, Connect, and Middleware that aren’t fully implemented, but before you’re ready to use them, think about whether you really need them.

Brevity is the soul of wisdom. Tediousness is the limbs and outward flourishes.

– William baptised