Skip to main content

Command Palette

Search for a command to run...

Redux Toolkit-Simplifying Redux Application State Management

Updated
4 min read
Redux Toolkit-Simplifying Redux Application State Management

Redux Toolkit is the officially recommended toolset for simplifying Redux development. It incorporates preset best practices, making it easier to create and manage Redux state.

1. Creating a Store

Use the configureStore function to create a Redux store, which automatically configures middleware, such as redux-thunk for handling asynchronous operations.

import { configureStore } from '@reduxjs/toolkit';
import rootReducer from './reducers';

const store = configureStore({
  reducer: rootReducer,
});

export default store;

2. Creating Reducer Slices

Redux Toolkit provides the createSlice API to create manageable state slices and automatically generate corresponding action creators.

import { createSlice } from '@reduxjs/toolkit';

const counterSlice = createSlice({
  name: 'counter',
  initialState: 0,
  reducers: {
    increment: (state) => state + 1,
    decrement: (state) => state - 1,
    reset: () => 0,
  },
});

export const { increment, decrement, reset } = counterSlice.actions;
export default counterSlice.reducer;

3. Dispatching Actions

In React components, use the useDispatch and useSelector hooks from react-redux to dispatch actions and access state.

import { useDispatch, useSelector } from 'react-redux';
import { increment, decrement, reset } from './counterSlice';

function Counter() {
  const dispatch = useDispatch();
  const count = useSelector((state) => state.counter);

  return (
    <div>
      <button onClick={() => dispatch(increment())}>+</button>
      <p>{count}</p>
      <button onClick={() => dispatch(decrement())}>-</button>
      <button onClick={() => dispatch(reset())}>Reset</button>
    </div>
  );
}

export default Counter;

Middleware Support

Redux Toolkit allows easy addition of custom middleware, such as redux-thunk, for handling asynchronous operations.

import { configureStore } from '@reduxjs/toolkit';
import thunk from 'redux-thunk';
import rootReducer from './reducers';

const store = configureStore({
  reducer: rootReducer,
  middleware: [thunk],
});

Performance Optimization

Use createAsyncThunk to create action creators for handling asynchronous operations, which automatically manage pending, fulfilled, and rejected states.

import { createAsyncThunk } from '@reduxjs/toolkit';

export const fetchUser = createAsyncThunk(
  'users/fetchUser',
  async () => {
    const response = await fetch('https://api.example.com/user');
    const data = await response.json();
    return data;
  }
);

Writing Selectors

Use createSelector (typically from the reselect library) to create efficient computed properties that recompute only when dependencies change.

import { createSelector } from 'reselect';

const selectUser = (state) => state.users.user;
const selectTotal = createSelector(
  [selectUser],
  user => user && user.totalPoints
);

export const selectTotalPoints = selectTotal;

Immutability in Redux

Redux Toolkit uses the immer library by default, allowing direct state modifications in reducers while automatically handling immutable updates.

import { createSlice } from '@reduxjs/toolkit';

const todoSlice = createSlice({
  name: 'todos',
  initialState: [],
  reducers: {
    addTodo: (state, action) => {
      // Directly modify state, immer handles immutability
      state.push({ text: action.payload, completed: false });
    },
    toggleTodo: (state, action) => {
      state[action.payload.index].completed = !state[action.payload.index].completed;
    },
  },
});

export const { addTodo, toggleTodo } = todoSlice.actions;
export default todoSlice.reducer;

Automatic Reducer Matching

When importing a slice’s reducer, Redux Toolkit automatically adds it to the store’s reducer object, eliminating the need for manual merging.

Code Splitting

For large applications, consider splitting state slices into multiple files and loading them on-demand to achieve code splitting.

Middleware Integration

Redux Toolkit makes it easy to add and manage multiple middlewares, such as logging or error handling.

Testing

Action creators and reducers created with createSlice are easier to unit test due to their clear logic.

Using TypeScript

Redux Toolkit integrates well with TypeScript, providing type safety for action creators, reducers, and the entire store.

CombineReducers

While createSlice simplifies state slice creation and management, you can still use combineReducers to combine multiple slices for more complex application structures.

Using RTK Query

Redux Toolkit provides the createApi function for managing API requests, similar to Apollo Client’s GraphQL queries. It handles caching, automatic retries, and subscriptions.

Performance Monitoring

Redux Toolkit integrates with Redux DevTools for convenient state change monitoring, including time-travel debugging and snapshot comparisons, which are invaluable for debugging and performance optimization.

Error Handling

Handle errors in asynchronous operations using the second parameter of createAsyncThunk, improving user experience.

export const fetchUser = createAsyncThunk(
  'users/fetchUser',
  async (_, thunkAPI) => {
    try {
      const response = await fetch('https://api.example.com/user');
      if (!response.ok) {
        throw new Error('Failed to fetch user');
      }
      return response.json();
    } catch (error) {
      // Errors are automatically handled and returned to the rejected case
      return thunkAPI.rejectWithValue(error.message);
    }
  }
);

Normalizing State Shape

For complex data structures, consider normalizing the state shape to reduce redundancy and improve query performance. The normalizr library can assist with this task.

Reducer Composition

You can use other reducer functions within a slice to compose complex business logic.

Middleware for Side Effects

Redux Toolkit allows middleware to handle side effects, such as network requests, scheduled tasks, or event subscriptions.

Reducer Logic Refactoring

If your application requires refactoring, you can easily split a large reducer into smaller, reusable parts and combine them using combineReducers.

Optimistic Updates

Use Redux Toolkit to implement optimistic updates, displaying expected results before data is actually updated to enhance user experience.

Code Generation

In large projects, consider using code generation tools like redux-starter-kit or custom scripts to automate the creation of slices and action creators.

Redux Toolkit provides numerous tools and best practices to help developers manage React application state more efficiently. By leveraging these features, you can build more robust and maintainable projects. In practice, continuous learning and exploration to find the best approach for your project’s needs is key to improving development efficiency.

Web Development

Part 21 of 46

The content covers the three basics of HTML/CSS/JS/TS, modular development, mainstream frameworks (Vue, React, Angular, Svelte), build tools, browser plug-in development, Node.js backend practice, Next.js/Nest.js and other popular technologies.

Up next

Web Workers and Service Workers-Background Processing and Offline Caching

Web Workers and Service Workers are two critical technologies in web development for handling background tasks and offline caching. They differ significantly in their working principles and use cases. Web Workers: Background Processing Web Workers en...

More from this blog

T

Tianya School Technical Articles

48 posts

Welcome to our tech publication, where we share high-quality content on full-stack development, frontend/backend/web3/AI, and engineering best practices.