My Learning Note on Redux (iii)

E.Y.
4 min readJun 25, 2020

--

Photo by Olivia Colacicco on Unsplash

In the previous section we talked about basics about Redux and a simple use case to use React-Redux. In this post I’m going to share about Asynchronous Actions in Redux (impure actions).

So a common scenario will be fetching data — before, after (when succeed), after(when fail). In each of this state, we will have data , error , loading status updated.

So create the folder structure as below, and under each put:

//userType.jsexport const FETCH_USERS_REQUEST = "FETCH_USERS_REQUEST";
export const FETCH_USERS_SUCCESS = "FETCH_USERS_SUCCESS";
export const FETCH_USERS_FAILURE = "FETCH_USERS_FAILURE";
//userAction.jsimport axios from "axios";
import {
FETCH_USERS_REQUEST,
FETCH_USERS_SUCCESS,
FETCH_USERS_FAILURE,
} from "./userTypes";
export const fetchUsers = () => {
return (dispatch) => {
//
It passes the dispatch method as an argument to the function,
// thus making it able to dispatch actions itself.
dispatch(fetchUsersRequest());
axios
.get("https://jsonplaceholder.typicode.com/users")
.then((response) => {
const users = response.data;
dispatch(fetchUsersSuccess(users));
})
.catch((error) => {
dispatch(fetchUsersFailure(error.message));
});
};
};
export const fetchUsersRequest = () => {
return {
type: FETCH_USERS_REQUEST,
};
};
export const fetchUsersSuccess = (users) => {
return {
type: FETCH_USERS_SUCCESS,
payload: users,
};
};
export const fetchUsersFailure = (error) => {
return {
type: FETCH_USERS_FAILURE,
payload: error,
};
};
//userReducer.js
import {
FETCH_USERS_REQUEST,
FETCH_USERS_SUCCESS,
FETCH_USERS_FAILURE,
} from "./userTypes";
const initialState = {
loading: false,
users: [],
error: "",
};
const reducer = (state = initialState, action) => {
switch (action.type) {
case FETCH_USERS_REQUEST:
return {
...state,
loading: true,
};
case FETCH_USERS_SUCCESS:
return {
loading: false,
users: action.payload,
error: "",
};
case FETCH_USERS_FAILURE:
return {
loading: false,
users: [],
error: action.payload,
};
default:
return state;
}
};
export default reducer;

There are a few points to note down here:

Async action creator:

Note that in the `fetchUsers function we returns a function instead of an object, this is because in store.js we have imported the redux-thunk middleware.

import { createStore, applyMiddleware } from “redux”;
import rootReducer from “./rootReducer”;
import thunk from “redux-thunk”;
const store = createStore(rootReducer, applyMiddleware(thunk));

Using this specific middleware, an action creator can return a function instead of an action object.

When an action creator returns a function, that function will get executed by the Redux Thunk middleware. This function doesn’t need to be pure; it is thus allowed to have side effects, including executing asynchronous API calls. Middleware like thunk basically wraps the store’s dispatchmethod and allows you to dispatch something other than actions, for example, functions or Promises.

Note that there are 2 kinds of reducer:

  • Pure Reducer action: triggers a reducer and changes state.
  • Impure Async action: triggers an async action. This may call a Reducer action inside it.

Complex action payload:

We can do more complex stuff to action payload than we thought, instead of just taking some of it’s property, we can do things like :

data: users.data.children.map(child => child.data)

Middleware:

If you used express before, you might be familiar with middleware already. Redux middleware provides a third-party extension point between dispatching an action, and the moment it reaches the reducer. People use Redux middleware for logging, crash reporting, talking to an asynchronous API, routing, and more.

For our async actions, Thunk middleware isn’t the only way to orchestrate asynchronous actions in Redux:

And last but not least, if you are interested in how the UI integrates with our Redux part: below is the code for UserContainer.js :

import React, { useEffect } from “react”;
import { connect } from “react-redux”;
import { fetchUsers } from “../redux”;
function UsersContainer({ userData, fetchUsers }) {
useEffect(() => {
fetchUsers();
}, []);
return userData.loading ? (
<h2>Loading</h2>
) : userData.error ? (
<h2>{userData.error}</h2>
) : (
<div>
<h2>Users List</h2>
<div>
{userData &&
userData.users &&
userData.users.map((user) => <p>{user.name}</p>)}
</div>
</div>
);
}
const mapStateToProps = (state) => {
return {
userData: state.user,
};
};
const mapDispatchToProps = (dispatch) => {
return {
fetchUsers: () => dispatch(fetchUsers()),
};
};
export default connect(mapStateToProps, mapDispatchToProps)(UsersContainer);

--

--

No responses yet