In this module, you'll learn about Redux Toolkit, a powerful library that simplifies Redux development. You'll explore how to create slices, handle async actions with Redux Thunk, and implement middleware in your Redux store.
Redux is a predictable state management library for JavaScript applications and is the most popular state container for React applications. As applications grow in size and complexity, managing state becomes increasingly challenging. Redux provides a solution to this problem.
The core concepts and principles of Redux are three-fold:
Everything that changes within your application is represented by a single JavaScript object known as the store. The store contains the entire state for your application.
When the application state changes, we clone the state object, modify the clone, and replace the original state with the new copy. We never mutate the original object, and we never write directly to our store object.
Given the same input, a pure function returns the same output every time. All functions (reducers) in Redux must be pure functions. They take in some state and a description of what changes took place (actions) and return a copy of our state.
Redux creates a more predictable state management flow, especially useful in larger applications where state management can become complex.
To use Redux with React, you need to set up a few key components:
Basic setup for Redux in a React application:
// Create a reducer const counterReducer = (state = { count: 0 }, action) => { switch (action.type) { case 'INCREMENT': return { count: state.count + 1 }; case 'DECREMENT': return { count: state.count - 1 }; default: return state; } }; // Create a store import { createStore } from 'redux'; const store = createStore(counterReducer); // Connect Redux to React import { Provider } from 'react-redux'; ReactDOM.render( <Provider store={store}> <App /> </Provider>, document.getElementById('root') );
With this setup, any component in your application can connect to the Redux store and access or update the state.
The Redux flow follows a specific pattern:
Action creators are functions that create and return action objects. They make it easier to dispatch actions:
// Action Types const INCREMENT = 'INCREMENT'; const DECREMENT = 'DECREMENT'; // Action Creators const increment = () => ({ type: INCREMENT }); const decrement = () => ({ type: DECREMENT }); // Dispatch in a component dispatch(increment());
With the useSelector
and useDispatch
hooks from React-Redux, you can connect components to the Redux store:
import { useSelector, useDispatch } from 'react-redux'; import { increment, decrement } from './actions'; function Counter() { // Get data from store const count = useSelector(state => state.count); // Get the dispatch function const dispatch = useDispatch(); return ( <div> <p>Count: {count}</p> <button onClick={() => dispatch(increment())}>+</button> <button onClick={() => dispatch(decrement())}>-</button> </div> ); }
By default, Redux action creators cannot contain side effects or asynchronous logic. Redux Thunk is middleware that allows you to write action creators that return a function instead of an action. This function can perform asynchronous operations and dispatch actions when ready.
Setting up Redux Thunk:
import { createStore, applyMiddleware } from 'redux'; import thunk from 'redux-thunk'; import rootReducer from './reducers'; const store = createStore( rootReducer, applyMiddleware(thunk) );
Creating an asynchronous action creator with Redux Thunk:
// Action Types const FETCH_USERS_REQUEST = 'FETCH_USERS_REQUEST'; const FETCH_USERS_SUCCESS = 'FETCH_USERS_SUCCESS'; const FETCH_USERS_FAILURE = 'FETCH_USERS_FAILURE'; // Action Creators const fetchUsers = () => { return async (dispatch) => { // Dispatch request action dispatch({ type: FETCH_USERS_REQUEST }); try { // Make API call const response = await fetch('https://api.example.com/users'); const data = await response.json(); // Dispatch success action with data dispatch({ type: FETCH_USERS_SUCCESS, payload: data }); } catch (error) { // Dispatch failure action with error dispatch({ type: FETCH_USERS_FAILURE, payload: error.message }); } }; };
Redux Thunk enables you to handle complex asynchronous workflows in your Redux applications, such as API requests, while maintaining the predictable state management that Redux provides.