An enhanced version of react useReducer hook for handling asynchronous logics with your own middlewares.
Middleware is a function that takes an action from dispatch, process some sync/async logics, and passes the action to reducer.
Be aware that it is not compatible with redux-middlewares.
$ npm install react-use-middleware-hook
$ yarn add react-use-middleware-hook
const [state, dispatch] = useMiddleware(reducer, initialState, middleware);
- reducer
- Type:
Function
- A pure function of type
(state, action) => newState
- Type:
- initialState(optional)
- Type:
any
- Type:
- middleware(optional)
- Type:
Function
orObject
orArray
- A function or a collection of functions of type
payload => newPayload
- Name of functions must be same as action types. Check below examples for detail.
- Type:
When dispatching an action, it MUST contains type property. Also, action may include payload property, if any value needs to be passed to middlewares or a reducer.
React useMiddleware hook provides two ways to use it.
- with middleware
- without middleware
Although both ways work fine, using middleware is recommended in the point of SOC(separation of concerns).
With middleware, useMiddleware hook accepts a middleware or collection of middlewares as 3rd parameter.
Middlewares may contain asynchronous logics.
//App.jsx
import useMiddleware from "react-use-middleware-hook";
import { loading, getPost, end } from "./actions";
import reducer from "./reducer";
import middleware from "./middleware";
export default function App() {
const [state, dispatch] = useMiddleware(reducer, { data: {} }, middleware);
const getPost = async postId => {
dispatch(loading());
await dispatch(getPost(postId));
dispatch(end());
};
return; /* some elements */
}
//actions.js
export const loading = () => ({ type: "loading" });
export const end = () => ({ type: "end" });
export const getPost = postId => ({ type: "getPost", payload: postId });
export const fetchError = err => ({ type: "fetchError", payload: err });
//middleware.js
import * as actions from "./actions";
//middleware function accepts a payload which dispatched from an action,
//and returns a new payload or triggers a different action.
const getPost = async postId => {
try {
const res = await fetch(
`https://jsonplaceholder.typicode.com/posts/${postId}`
);
const data = await res.json();
return data;
} catch (err) {
return actions.fetchError(err);
}
};
export default { getPost }; //exports an object which contains middleware functions in it.
//reducer.js
const reducer = (state, { type, payload }) => {
switch (type) {
case "loading":
return { ...state, status: "loading" };
case "end":
return { ...state, status: "end" };
case "getPost":
return { ...state, data: payload };
case "fetchError":
return { ...state, error: payload };
default:
return state;
}
};
export default reducer;
Without middleware, leave the 3rd parameter empty. In this case, actions may contain asynchronous logics.
//App.jsx
import useMiddleware from "react-use-middleware-hook";
import { loading, getPost, end } from "./action";
import reducer from "./reducer";
export default function App() {
const [state, dispatch] = useMiddleware(reducer, { data: {} });
const getPost = async postId => {
dispatch(loading());
await dispatch(getPost(postId));
dispatch(end());
};
return; /* some elements */
}
//actions.js
export const loading = () => ({ type: "loading" });
export const end = () => ({ type: "end" });
export const getPost = async postId => {
try {
const res = await fetch(
`https://jsonplaceholder.typicode.com/posts/${postId}`
);
const data = await res.json();
return { type: "getPost", payload: data };
} catch (err) {
return fetchError(err);
}
};
export const fetchError = err => ({ type: "fetchError", payload: err });
//reducer.js
const reducer = (state, { type, payload }) => {
switch (type) {
case "loading":
return { ...state, status: "loading" };
case "end":
return { ...state, status: "end" };
case "getPost":
return { ...state, data: payload };
case "fetchError":
return { ...state, error: payload };
default:
return state;
}
};
export default reducer;