In the last article, we integrated synchronous Redux into our project. In this article, we will use asynchronous Actions to optimize our code in Redux

State

Let’s remember our store type first

type Person = {
  id: number;
  name: string;
};
type AppState = {
  people: Person[];
};
Copy the code

so? Our store contains a people field, which is an array type containing id/name

We just need to define some cleaner store states so we can focus on the Redux Store and how the React component interacts with it in a strongly typed way.

Use asynchronous actions to modify the state in the store

We use Redux Thunk middleware to implement Redux’s asynchronous action.

Where do you add this thing? Add applyMiddleware when creating a store, i.e., createStore. ApplyMiddleware is an API from Redux that allows you to add middleware to the Store

import { combineReducers, createStore, applyMiddleware } from 'redux';
import type { Store } from 'redux';
import thunk from 'redux-thunk';

import type { AppState } from './data.d';

import peopleReducer from './reducers/index';

const rootReducer = combineReducers<AppState>({
  people: peopleReducer,
});

function configureStore() :Store<AppState> {
  const store = createStore(rootReducer, undefined, applyMiddleware(thunk));
  return store;
}

const storeData = configureStore();

export default storeData;

Copy the code

Actions and actions create functions

Now, let’s change the action creation function to be asynchronous. Here is the asynchronous action with the user name added

// src/redux/actions/index.ts
import type { Dispatch } from "redux";

function wait(ms: number) :Promise<void> {
  return new Promise((resolve) = > setTimeout(resolve, ms));
}

const addPerson = (personName: string) = > async (
  dispatch: Dispatch<AddPersonAction>
) => {
  await wait(200);
  dispatch({
    type: "AddPerson".payload: personName,
  } as const);
};
Copy the code

In our example, we are forgery an asynchronous operation (such as an interface request) with the WAIT delay function.

  • addPersonFunction returns a function, rather than an Action object like the original synchronous function.
  • The inner function takes one argumentdispatchFunction that dispatches an action

Note that we explicitly set the type of the Dispatch parameter using Dispatch

. Dispatch is a generic type provided by Redux, and we pass the type AddPersonAction to Dispatch.

Here is the definition of the AddPersonAction type

type AddPersonAction = {
  readonly type: "AddPerson";
  readonly payload: string;
};
Copy the code

Next, we modify the action creation function to delete the user

// src/redux/actions/index.ts
type RemovePersonAction = {
  readonly type: "RemovePerson";
  readonly payload: number;
};
const removePerson = (id: number) = > async (
  dispatch: Dispatch<RemovePersonAction>
) => {
  await wait(200);
  dispatch({
    type: "RemovePerson".payload: id,
  } as const);
};
Copy the code

Reducer

The action parameter types in Reducer are different from those in the synchronous version

type Actions = AddPersonAction | RemovePersonAction;
Copy the code

In the synchronized version of the code, we implemented the action type with TS’s automatic type, but here we need to create the action type.

The reducer functions are the same as those of the synchronized version

function peopleReducer(state: Person[] = [], action: Actions) {
  switch (action.type) {
    case "AddPerson":
      return state.concat({
        id: state.length + 1.name: action.payload,
      });
    case "RemovePerson":
      return state.filter((person) = >person.id ! == action.payload);default:
      neverReached(action);
  }
  return state;
}

function neverReached(never: never) {}
Copy the code

Link component

Connect the React component to the Store. UseSelector is used to get data from the store

const people: Person[] = useSelector((state: AppState) = > state.people);
Copy the code

UseDispatch dispatches the action

constdispatch = useDispatch(); .const handleSubmit = (e: React.FormEvent<HTMLFormElement>) = >{ e.preventDefault(); dispatch(addPerson(newPerson)); . }; .const dispatchNewPerson = (id: number) = > () = >{ dispatch(removePerson(id)); }; . <button onClick={dispatchNewPerson(person.id)}>Remove</button>Copy the code

conclusion

Redux needs libraries like Redux Thunk to handle asynchronous operations.

Async action creation returns a function that dispatches an action(note: the action creation function in a synchronous Redux returns an object)

However, there is a popular library called Redux Saga that handles asynchronous Redux operations, which we will cover briefly later

Reference documentation

www.carlrippon.com/managing-ap…