In JavaScript development, Redux stands tall as a robust library designed to tackle the complexities of application state management. Historically, Redux has been a cornerstone in developers’ toolkits working on large-scale React applications. However, despite its initial prominence, several drawbacks have led to a decline in its popularity:
For more details, refer to the article You Might Not Need Redux.
Fortunately, the landscape of state management solutions has evolved, presenting the Redux Toolkit as an alternative. Developed in response to the aforementioned pain points, the Redux Toolkit offers a streamlined approach to development.
In this blog, we’ll see the advantages of Redux Toolkit, including its efficiency and simplicity compared to its predecessor.
Redux Toolkit is a method to write Redux logic. It was introduced by simplifying common Redux use cases and addressing the major Redux drawbacks. It supports the most-used Redux add-ons, like Redux Thunk (for async tasks), Immer (for handling immutability in stores), and Reselect (to select a slice out of the global store).
Redux Toolkit works extensively in the background to simplify application state management by abstracting the Redux API.
As an example, let’s see a simple comparison between these two technologies to create a Redux store.
With Redux
// src/app/store.js import { configureStore, createSlice } from '@reduxjs/toolkit'; const counterSlice = createSlice({ name: 'counter', initialState: { value: 0 }, reducers: { increment: (state) => { state.value += 1; }, decrement: (state) => { state.value -= 1; }, }, }); export const { increment, decrement } = counterSlice.actions; export default configureStore({ reducer: { counter: counterSlice.reducer, }, });
With Redux Toolkit:
// src/app/store.js import { configureStore, createSlice } from '@reduxjs/toolkit'; const counterSlice = createSlice({ name: 'counter', initialState: { value: 0 }, reducers: { increment: (state) => { state.value += 1; }, decrement: (state) => { state.value -= 1; }, }, }); export const { increment, decrement } = counterSlice.actions; export default configureStore({ reducer: { counter: counterSlice.reducer, }, });
As you can see in the previous example, Redux Toolkit reduces the boilerplate and complexity involved in setting up a Redux store compared to the classic Redux approach. Redux involves manually configuring middleware, reducers, and sometimes enhancers, whereas the Redux Toolkit uses configureStore to set up the store and manages reducers with createSlice. That makes Redux Toolkit the more appealing and efficient approach.
Several Redux Toolkit API functions add much value as abstract versions of Redux API functions. They add more manageability and aid in streamlining the Redux flow.
We can use these to simplify the boilerplate code.
This function creates a Redux store instance and is an abstraction of the Redux createStore(). But the configuration here is simplified, enables the Redux DevTools Extension, and includes redux-thunk by default.
This function defines an action creator function by accepting an action type string.
Refer to the following code example.
import { createAction } from '@reduxjs/toolkit'; // Create action creators. const increment = createAction('counter/increment'); const decrement = createAction('counter/decrement'); // Passing a payload with the action. const incrementByAmount = createAction('counter/incrementByAmount'); console.log(incrementByAmount(5));
The createAction combines the action type constant and action creator function from Redux.
This helps us to create a reducer function more simply. It allows us to map action types directly to case reducer functions to update the state when an action is dispatched. In addition, it uses the Immer library automatically to simplify the immutable update logic with mutative code.
Refer to the following code example.
import { createReducer } from '@reduxjs/toolkit'; // Initial state. const initialState = { value: 0 }; // Create reducer. const counterReducer = createReducer(initialState, (builder) => { builder .addCase(increment, (state, action) => { state.value += 1; }) .addCase(decrement, (state, action) => { state.value -= 1; }) .addCase(incrementByAmount, (state, action) => { state.value += action.payload; }); }); export default counterReducer;
This function automatically generates action creators and action types by accepting a slice name, the initial state, and an object of reducer functions. It generates a slice of the store and simplifies the process even more.
In Redux, we must manage the actions and their corresponding actions inside the reducers. But unlike in Redux, all the actions and reducers are present within the same slice when using createSlice.
This function accepts a Redux action type string and a callback function that should return a promise and abstract the recommended method of handling async lifecycles.
We can use this function to create a set of prebuilt reducers and selectors to perform CRUD operations on a normalized database.
The previous code snippets and the key features show how much easier it is to use the Redux Toolkit instead of the traditional Redux approach.
In this tutorial, we’ll explore using Redux Toolkit to create a basic book management application. We’ll go through each step, from setting up the project to interacting with the Redux store in React components.
First, let’s create a new React project and install the necessary libraries:
// create a React app. npx create-react-app app-name // install Redux Toolkit and React Redux. npm install @reduxjs/toolkit react-redux
Next, we’ll create a Slice for managing books. This slice will handle adding and deleting books.
// src/features/book/bookSlice.js import { createSlice } from '@reduxjs/toolkit'; export const bookSlice = createSlice({ name: 'book', initialState: [], reducers: { addBook: (state, action) => { // Directly mutating the state is safe inside createSlice thanks to Immer. state.push(action.payload); }, deleteBook: (state, action) => { return state.filter(book => book.id !== action.payload.id); }, }, }); export const { addBook, deleteBook } = bookSlice.actions; export default bookSlice.reducer;
The addBook will take a book object as a payload and add it to the current state, whereas the deleteBook removes a book based on the provided ID.
Now, let’s configure the Redux store.
// src/app/store.js import { configureStore } from '@reduxjs/toolkit'; import bookReducer from './../features/book/bookSlice'; export default configureStore({ reducer: { book: bookReducer, }, });
Now, we can use the store we’ve created in our application by wrapping the app’s component tree with the Provider component from react-redux.
// src/index.js // ... import { Provider } from 'react-redux'; import store from './app/store'; // ... <Provider store={store}> <App /> </Provider> // ...
Finally, we’ll interact with the Redux store from our components using hooks like useSelector to access the state and useDispatch to dispatch actions.
// src/features/book/BookComponent.js // ... import { addBook, deleteBook } from './bookSlice'; const BooksComponent = () => { const books = useSelector((state) => state.book); const dispatch = useDispatch(); const [newBookTitle, setNewBookTitle] = useState(''); const handleAddBook = (e) => { e.preventDefault(); const newBook = { id: Date.now(), title: newBookTitle, }; dispatch(addBook(newBook)); setNewBookTitle(''); }; const handleDeleteBook = (bookId) => { dispatch(deleteBook({ id: bookId })); }; return ( // ... book list }; export default BooksComponent;
Thus, we’ve built a simple book management application using Redux Toolkit.
For more details, refer to the complete sample project on GitHub.
As you’ve experienced in the previous example, the Redux Toolkit makes the development of Redux apps much faster and more straightforward.
We can use the Redux Toolkit at the beginning of a new project or as an incremental migration to an already-developed project.
Advantages:
So, why not use this optimized solution to gain maximum efficiency and manageability over Redux?
Redux Toolkit saves precious time you must invest in the project and even reduces the amount of code a developer must write. One of the best things about it is that its support is not limited to React but extends to frameworks like Angular, also.
Implementing the Redux Toolkit could be the step you need to take toward more simplified and efficient state management. I hope this article helped you get a clear picture of the transformative potential of Redux Toolkit.
The Syncfusion React JS UI component library is the only suite you will ever need to build an application. It contains over 80 high-performance, lightweight, modular, and responsive UI components in a single package.
Those familiar with Syncfusion can download the product setup from the Downloads page. If you’re new to Syncfusion, we welcome you to take advantage of our complimentary 30-day trial to explore our offerings firsthand.
If you have any questions or need assistance, please don’t hesitate to contact us through our support forum, support portal, or feedback portal. Our team is here and ready to assist you at every stage.
Thank you for reading!