Those of you who have used Vuex must know that vuex is much less difficult to integrate and get started than React-Redux. Currently, to achieve the same functions of Vuex, three libraries are required, namely Redux, React-Redux and Redux-Saga, which are responsible for the following tasks respectively.

  • Redux: Redux is a JavaScript state container that provides predictable state management.
  • React-Redux: a library that binds React projects to Redux projects.
  • Redux-saga: A library for managing Side effects (Side effects, such as asynchronously fetching data, accessing browser caches, etc.) in applications. Its goal is to make Side effects management easier, execution more efficient, testing easier, and handling failures easier.

However, due to the complexity of Redux-Saga, this article will not talk about Redux and React-Redux for the time being. Because of the high cost of these libraries, Ant Financial launched an integration library DVA, which integrates these three libraries. React-router and FETCH are also built in, but Redux and React-Redux still have to learn from the popularity.

So when to use Redux, here’s my idea: You can use Redux when communication between components is giving you a headache.

Especially in an interface where there are a lot of forms to fill out, you need to unify the data and send it to the back end, because you can’t not split the form into components, once the form components are split, the data transfer inside will be very complicated. Of course, there is another solution is not to split the component, all in one component (I have actually seen this form component, before the formatting 4000 lines of code, a formatted over 1W lines, and almost no comments, you do not know what the code is doing, directly can not maintain…). .

Like Vue, in a large project or a project with complex communication, it is very troublesome and difficult to implement communication between sibling and grandparent components (although I recently learned that React has Context). In order to solve this problem, The React project introduced Redux and React-Redux. It is worth noting that Redux can be used not only in the React project, but also in projects with other frameworks.

Let’s try Redux first:

1. Use Redux

There are several steps to Redux:

  1. Create the state.
  2. Create the action.
  3. Communicate through Dispatch.

Of course this is my summary of the feeling that language is not official… Let’s take a look at each of the three steps.

1.1 create the state

Because I love TypeScript so much, the following code uses TypeScript.

interface action {
  type: "INCREMENT" | "DECREMENT";
}

const counter = (state = 0, action: action) = > {
  switch (action.type) {
    case "INCREMENT":
      return state + 1;
    case "DECREMENT":
      return state - 1;
    default: // Do not forget the default return value, otherwise the creation of an error
      returnstate; }};Copy the code

1.2 create the Store

const store = createStore(counter);

store.subscribe(() = > console.log(store.getState())); // The callback that is triggered when properties in the store change
Copy the code

Subscribe (() => console.log(store.getstate ()))); This statement, but we add this statement so that we can clearly see the changes in store when we communicate with each other.

1.3 communication

store.dispatch({ type: "DECREMENT" }); // Trigger state + 1
store.dispatch({ type: "INCREMENT" }); // Trigger state-1
Copy the code

{type: “DECREMENT”} can be defined as a function.

const increment = (): action= > ({
  type: "INCREMENT"});const decrement = (): action= > ({
  type: "DECREMENT"}); store.dispatch(increment()); store.dispatch(decrement());Copy the code

For the string “INCREMENT”, it is recommended to define it as a constant, because after all {type: The “INCREMENT” string in “INCREMENT”} is written without prompting, which is very easy to get wrong, but TypeScript prompts it, which is one of TypeScript’s great things.

TypeScript also displays an error if you make a typo:

As a result, in JavaScript, a string like “INCREMENT” is written without prompting, so many people define a constant for it in case of writing errors (though TypeScript also recommends doing this).

const INCREMENT_TYPE = "INCREMENT";  // Define constants

const increment = (): action= > ({
  type: INCREMENT_TYPE, // call with constants
});

store.dispatch(increment());
Copy the code

Once a constant is defined, it gets code hints and is less prone to writing errors.

1.4 the value

You can also pass in a parameter in store.dispatch(), which is usually called payload or data.

interface action {
  type: "INCREMENT" | "DECREMENT"; payload? :number;    // The passed parameter is usually named payload or data
}

const INCREMENT_TYPE = "INCREMENT";

const increment = (nr: number) :action= > ({
  type: INCREMENT_TYPE,
  payload: nr,
});

const decrement = (): action= > ({
  type: "DECREMENT"});const counter = (state = 0, action: action) = > {
  switch (action.type) {
    case "INCREMENT":
      return state + (action.payload as number);
    case "DECREMENT":
      return state - 1;
    default:
      returnstate; }};const store = createStore(counter);

store.subscribe(() = > console.log(store.getState()));

store.dispatch(increment(5));
store.dispatch(decrement());
Copy the code

2. React-Redux

React-redux: React-redux: React-redux: React-redux: React-redux: React-redux: React-redux: React-Redux: React-Redux Both hooks make it easy to access the state in the Store and trigger the behavior within it.

Since it is a project engineering document, it must be modular. Although the above writing method is also ok, it will bring great difficulties to the later maintenance. At present, MY habit is divided into:

Modules puts things related to state, such as this code, in modules:

const counter = (state = 0, action: action) = > {
  switch (action.type) {
    case "INCREMENT":
      return state + (action.payload as number);
    case "DECREMENT":
      return state - 1;
    default:
      returnstate; }};Copy the code

Actions puts the code that triggers the event. For example, the following code is placed in a file in the Actions folder:

export interface action {
  type: "INCREMENT" | "DECREMENT"; payload? :number;
}

const INCREMENT_TYPE = "INCREMENT";

export const increment = (nr: number) :action= > ({
  type: INCREMENT_TYPE,
  payload: nr,
});

export const decrement = (): action= > ({
  type: "DECREMENT"});Copy the code

The index.ts file under store consolidates all the above files into a store and exports them. You can also add Redux debugging tools. For details about Redux debugging tools, click:

import { combineReducers, createStore } from "redux";
import counter from "./modules/counter";
import isLogged from "./modules/isLogged";

/ / integration
const allReducers = combineReducers({ counter, isLogged });

/ / register
const store = createStore(
  allReducers,
  // @ts-ignore
  window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__() // Introduce the Redux debugging tool
);

/ / export
export default store;
Copy the code

The final step is that we need to introduce and use react-Redux in our projects.

import { Provider } from "React-Redux";
import store from "./store";

ReactDOM.render(
  <Provider store={store}>
    <React.StrictMode>
      <App />
    </React.StrictMode>
  </Provider>.document.getElementById("root"));Copy the code

The Provider above is a top-level component that registers a store that all components can access.

So far, we’ve registered the Store in the React project, so we can access the store data in the component whenever we need it.

Two hooks need to be used, and other hooks can be referred to the reference link at the end of the article:

  • UseSelector: Extracts data from Redux storage state.
  • UseDispatch: This hook returns a dispatch function that triggers actions.

2.1 Invocation in components

Once you know the above two hooks, you can start doing things.

import React from "react";
import "./App.css";
import { useDispatch, useSelector } from "react-redux";
import { increment } from "./store/actions";

interface AllState {
  counter: number;
  isLogged: boolean;
}

function App() {
  // useSelector declares a generic type, the first being the type of state and the second representing the type of the return value
  // The following code counter is of type number
  const counter = useSelector<AllState, AllState["counter"> ((state) = > state.counter
  );
  const isLogged = useSelector<AllState, AllState["isLogged"> ((state) = > state.isLogged
  );
  Calling useDispatch returns a dispatch function
  const dispatch = useDispatch();
  return (
    <div className="App">{counter} {isLogged ? "1", "2"}<button onClick={()= >Dispatch (increment (5))} > point me</button>
    </div>
  );
}

export default App;
Copy the code

For code demonstration purposes, the AllState interface is declared directly in the component, and in index.ts is generally recommended.

2.2 Solving Type Duplication

If your project is big enough and you have a lot of actions, there is a chance that action types will be repetitive, which can cause bugs. I know of two solutions to this problem:

One is to introduce namespaces, such as XXX/before strings, as vuex does.

export interface action {
  type: "a/INCREMENT"; payload? :number;
}

export const INCREMENT_TYPE = "a/INCREMENT"; // Introduce the namespace

export const increment = (nr: number) :action= > ({
  type: INCREMENT_TYPE,
  payload: nr,
});
Copy the code

One is to use symbol:

export interface action {
  type: symbol; payload? :number;
}

export const INCREMENT_TYPE = Symbol("INCREMENT");

export const increment = (nr: number) :action= > ({
  type: INCREMENT_TYPE,
  payload: nr,
});
Copy the code

Both approaches solve the problem of type duplication.

3. The last

So far, you can happily use Redux in your projects, but one drawback is that you can’t handle asynchronous requests. If you need to handle asynchronous requests, you need to use Redux-Saga or redux-Thunk.

Explains the contents of this article is very basic, but I saw the story, the React – story and other functions, because I didn’t use to so I don’t talk for a while ~ ~ ~ ~ (in fact is I’m not going to), by the way, update the hooks of the React – story is really very good, Because I used class in the tutorial when I first learned React, I felt there were a lot of inconveniences compared with VUex.

References:

React-Redux Hooks