State management - a concept that while uncomplicated at first, soon spirals into a complexity that can make even the most cool-headed developers pause for thought. Redux enforces a one-way data flow that makes it easier to understand an application’s state as a developer. Now, let’s elevate our mastery of Redux and immerse ourselves into the more advanced world of Redux.
The first step is to understand that Redux is not an architecturally-dictated library, but it is a set of tools and functions that are to be used as needed—where needed 1.
Middlewares in Redux
Redux middleware provides a third-party extension point between dispatching an action, and the moment it reaches the reducer, thus useful for logging, crash reporting, and the like 2.
Here’s an illustrative example from Redux’s own Github repository:
import { createStore, applyMiddleware } from 'redux';
function logger({ getState }) {
return (next) => (action) => {
console.log('will dispatch', action);
const returnValue = next(action);
console.log('state after dispatch', getState());
return returnValue;
};
}
const store = createStore(
reducer,
applyMiddleware(logger)
);
Working with Async Operations
When it comes to data fetching and handling, Redux allows for it to be called from:
- The view layer (React components)
- Middleware
- Thunks
I strongly recommend taking the route of Thunks when dealing with asynchronous actions. This is because in Redux’s middlewares, you can write action creators that return a function instead of an action object. This function gets dispatch method and getState as parameters 3.
Here’s a brief example:
export const fetchUser = userId => async dispatch => {
dispatch(userActions.fetchUserRequest())
const user = await userAPI.fetchUser(userId)
dispatch(userActions.fetchUserSuccess(user))
}
store.dispatch(fetchUser(5))
Redux DevTools
Would highly recommend Redux DevTools for debugging your Redux apps 4. With features like hot reloading, action replay, and customizable UI, Redux DevTools makes development a breeze. To install it as a Chrome extension, you can check their Github repo here.
Immutable State Updates
In Redux, state is read-only and changes should be made in an immutable manner. As pointed out by Dan Abramov, one of the authors of Redux, “The key to update state in Redux is to always make changes immutably. This means to make a copy of every piece of data that is changing, and apply the updates to the copies “5.
Here’s an example of the difference:
// Mutable update
state.field = newValue;
// Immutable update
state = { ...state, field: newValue };
Normalizing State Shape
In Redux, normalizing your state shape is instrumental in reducing redundancy in your state and can make many state updates easier. As described by Redux documentation, it’s a good practice to keep your state as dictionaries, where items can be looked up by id 6.
Conclusion
It’s all too easy to get overwhelmed with Redux due to its sophisticated architecture and verbose syntax. With careful and mindful implementation, Redux can be truly a game-changer for your applications, providing predictable state updates that are easy to test and debug.
Keep your reduced functions small, your action creators clean, and always make sure to handle errors appropriately. As always, happy coding!
Mark Erikson. (2016) Why Redux might not be for you. ↩︎
Redux docs. (2022) Middleware - Redux. ↩︎
Dan Abramov. (2016). Idiomatic Redux: The Tao of Redux, Part 2 - Practice and Philosophy. ↩︎
Redux docs. (2022) Redux DevTools. ↩︎
Dan Abramov. (2016). You Might Not Need Redux. ↩︎
Redux docs. (2022) Normalizing State Shape. ↩︎