Have you ever wanted to use Redux, but you didn’t because it requires too much boilerplate code? Configuring a Redux store is complicated and you need several packages to get Redux to work with React. Now, there is a much easier and faster way to integrate Redux into your React project: Redux Toolkit. We will cover the first part of the story in this article. In part II, we will go deeper into using Redux Toolkit and its latest addition: RTK Query.
Let’s learn about Redux Toolkit, known as “the official, batteries-included, opinionated toolset for efficient Redux development”. We will discuss why the Redux Toolkit deserves more attention in the React community.
Redux Toolkit also includes a powerful data fetching and caching capability that we've dubbed "RTK Query". It's included in the package as a separate set of entry points. It's optional but can eliminate the need to hand-write data fetching logic yourself. The next article (part II) will demonstrate how RTK Query can be used in real-world scenarios.
What is Redux?
In frontend frameworks like React, each component internally manages its own states. As the app gets more and more complex, managing states across many components becomes tedious, complicated, and difficult. Redux became the solution for this issue.
Redux works by providing a centralized and predictable ‘store’, single source of truth, which holds all the states within the app. Each component in the app can access this store without having to pass props around in the component tree.
How does Redux work?
The typical Redux flow is:
- A user interacts with the View (component) and triggers a state update
- When a state update is required, the View dispatches an action
- The reducers receive the action from the dispatch and update the state in the Store according to what is described by the action
- The View is subscribed to the Store to listen for state changes. The changes are notified via the subscription methods and the View updates its UI accordingly
Redux flow is next with 3 main parts - Store, Actions, and Reducers.
The state will be updated in the Store. The Store is where all the states are managed. It can be created in a single line.
The type of action is simply a string that describes the action, and the added properties are information that is needed to update the state. An action is dispatched via the store.dispatch(action) method and reducers handle the updating of the state.
Reducers are pure functions that take in the current value of a state, perform the operations on it as instructed by the action, then output the new value of the state. They are the ones responsible for changing the value of the state. Here’s a simple example of a reducer function.
The components must be subscribed to the Store and listen for state updates to render the states correctly in the UI. The store.subscribe() method adds a change listener that will be called whenever an action is dispatched.
The problem with Redux
Redux is a popular choice for state management. Its pattern makes states predictable, as reducers are pure functions, which means the same state and actions passed will always result in the same output.
It is also easily maintainable and scalable due to the strict organization on how each part in the Redux flow should behave and work. Also, there are many other benefits such as efficient testing, easy debugging, and better performance that Redux brings to the table.
React and Redux are believed to be the best combo for managing states in large-scale React applications. However, with time, the popularity of Redux has fallen due to the following reasons:
- Configuring a Redux store is not simple.
- Several packages are needed to get Redux to work with React.
- Redux requires too much boilerplate code.
- Writing actions and reducers becomes more complex and cumbersome in huge applications.
With these issues, the creator of Redux Dan Abramov published the article called 'You Might Not Need Redux', which advises people to use Redux only when it is needed and to follow other methods when developing less complex applications. And also:
Redux Toolkit - a New Way of Writing Redux
The Solution to the Problem
To overcome the challenges Redux had, the Redux team came up with Redux Toolkit, the official recommended approach for writing Redux logic. It aims to speed up Redux development by including Redux Core with the packages that they think are essential for building a Redux app. It is an opinionated derivative of Redux, with many best-practice configurations for Redux beginners or developers who want simple, fast, and clean Redux code.
Redux Toolkit (previously known as Redux Starter Kit) provides some options to configure the global store and create both actions and reducers more streamlined by abstracting the Redux API as much as possible.
- As mentioned earlier in previous versions of Redux a lot of boilerplate code was required to do simple things like having statuses for load or error. We'll go into this in detail later in part II, but RTK Query is a package included in the Toolkit that will introduce more or less the same magic as react-query and all that boilerplate code will be significantly reduced.
- The other biggest gripe with Redux development was the need to install a lot of packages depending on what you want to do, for example when going from client state to managing server state, middleware and thunk were required. Inside the Toolkit, you will have everything you need.
- As in the first point, configuring the store was complicated and with a lot of boilerplate code. Now, the process is an abstraction and they already have a lot of configuration done for us.
Redux Toolkit is an abstraction and an updated version of the common Redux that tries to standardize the way of managing the state with Redux.
For TypeScript users, Redux Toolkit has been built with TS in mind, meaning that typing is much easier than with previous versions of Redux while many types will be provided automatically.
The Redux Toolkit comes with several useful packages installed with it like Immer, Redux-Thunk, and Reselect. It makes life easier for React developers, allowing them to mutate state directly with less code (Immer handles immutability), and apply middleware like Thunk (which handles async actions) out of the box. It also uses Reselect, a simple “selector” library for Redux, to simplify reducer functions and optimize the code.
Redux Toolkit API
The following API function is used by Redux Toolkit, which is an abstract of the existing Redux API functions. These functions do not change the flow of Redux but only simplify and streamline them in a more readable and manageable manner.
- configureStore: Creates a Redux store instance as the original createStore from Redux, but accepts a named options object and sets up the Redux DevTools Extension automatically.
- createAction: Accepts an action type string and returns an action creator function that uses that type.
- createReducer: Accepts an initial state value and a lookup table of action types to reducer functions, and creates a reducer that handles all action types.
- createSlice: Accepts an initial state and a lookup table with reducer names and functions and automatically generates action creator functions, action type strings, and a reducer function.
You can use the above APIs to simplify the boilerplate code in Redux, especially using the createAction and createReducer methods. However, this can be further simplified using createSlice, which automatically generates action creator and reducer functions.
So let’s get started with Redux Toolkit and set it up with a new React app.
Step 1: Install Dependencies
To get started with Redux Toolkit and React-Redux packages, you can run the following command on an existing React app.
Create React App with.
Step 2: Create, Configure and Initialize Store
Let’s create a store to hold our states. Create a store.ts file in our src folder and add the following code to it.
The configureStore API here replaces the original createStore from Redux API. Unlike createStore, configureStore from Redux Toolkit not only creates a store, but it can also accept reducer functions as arguments and automatically set up the Redux DevTools Extension for easy and fast debugging, taking the Redux experience to the next level.
Step 3: Provide Store in React app
Once the store is created, every component in our React app needs to be able to access it. It can be done using the Provider from the react-redux package installed.
In the index.ts file, import the Provider and store.ts like:
Step 4: Write Reducers and Actions
Now write some reducer functions and actions for our Redux store.
In the traditional Redux, usually write reducers and actions separately. For example, a simple reducer and action for a counter app will be written in traditional Redux in the following ways.
With Redux Toolkit, you can make the code much more concise, in one place, by using createSlice. Create a counterSlice.ts file in the src folder of the app. Both the reducers and actions can be written under the following slice.
In the code above, defining reducers and actions becomes much easier, cleaner and faster in Redux Toolkit. There is no longer a need to use the switch statements to manage the action with its corresponding reducer.
The second thing is that it seems like it is directly mutating the state’s value in the reducer function instead of returning a new value to update the state. This is actually because Redux Toolkit uses the Immer library, which allows writing “mutating” logic in reducers. This leads to faster development and easier testing.
Step 5: Import Reducer to Store
Export reducers and actions from counterSlice.ts. So let’s import the reducer into store.ts.
Step 6: Dispatch Actions from React UI Component
As learned earlier, the View triggers an action to be dispatched in order to update a state. In Redux, use store.dispatch(action) to dispatch an action.
Instead, let’s use React-Redux to use the useDispatch hook to dispatch actions and useSelector to read data from the store.
Create a Counter.ts file in our src folder to represent the Counter component. In this file, import useDispatch and useSelector hooks from React-Redux. Also, import our actions from counterSlice.ts.
The counter function will initialize two hooks and return UI elements with our dispatch (action), triggered when clicked.
Redux Toolkit is a great option, for both beginners and experienced developers, to use when getting started with Redux or refactoring current projects with Redux. It simplifies the code and helps manage the Redux state by reducing the boilerplate code. It allows us to write cleaner and more readable code while keeping the Redux flow and pattern.
Keep in mind that Redux Toolkit is:
- Simple: Includes utilities to simplify common use cases like store setup, creating reducers, immutable update logic, and more.
- Opinionated: Provides good defaults for store setup out of the box, and includes the most commonly used Redux add-ons built in.
- Powerful: Takes inspiration from libraries like Immer and Autodux to let you write "mutative'' immutable update logic, and even create entire "slices” of state automatically.
- Effective: Lets you focus on the core logic your app needs, so you can do more work with less code.
Finally, just like Redux, Redux Toolkit is not built just for React. It can be used with any other frameworks such as Angular. You can find more information on the Redux Toolkit by referring to their documentation.
Thank you for reading!
About the Author
Bojan Golubovic is a software engineer with 7+ years of experience who loves helping companies to build products that can take their business to the next level using the latest technologies. Bojan is working at our development center in Niš.
Bojan is focused on enterprise solutions systems, mostly on SaaS products. Very satisfied that he had a chance to work with big companies, huge teams, and large projects. Making customers happy is something that leads him. Agile lover. As a Frontend oriented person, developer and architect of different solutions, Bojan has the ability to provide creativity as well as high standards.