DEV Community

Tianya School
Tianya School

Posted on

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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],
});
Enter fullscreen mode Exit fullscreen mode

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;
  }
);
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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);
    }
  }
);
Enter fullscreen mode Exit fullscreen mode

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.

Top comments (1)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.