Predictable State

Redux Toolkit

Redux Toolkit est la manière moderne et officielle d'écrire du Redux. Il élimine le code répétitif, inclut Immer pour les mises à jour immuables et intègre les devtools, le middleware et RTK Query.

intermediate15 min readUpdated 15 sept. 2026
counterSlice.js
js
// features/counter/counterSlice.js
import { 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 counterSlice.reducer;
Basé sur
Redux
Immuabilité
Immer, intégré
Configuration du store
configureStore
Logique
createSlice
Async
createAsyncThunk, RTK Query
Devtools
Activés par défaut

Pourquoi c'est important

Pourquoi Redux garde sa place

Prévisible par conception

Les changements d'état passent uniquement par des actions et des reducers purs, rendant chaque transition traçable et testable.

Devtools avec voyage dans le temps

Inspectez chaque action, comparez les états et rejouez l'historique, ce qui rend les bugs complexes reproductibles.

Batteries included

Immer, le middleware, les devtools et une couche de récupération de données sont livrés ensemble, réduisant considérablement le code de configuration.

Le tableau complet

Les trois idées derrière Redux

Un store unique, des reducers purs et des actions dispatchées. Toolkit conserve ces idées tout en supprimant la lourdeur administrative.

Le store

Source unique

Un seul objet détient l'état de l'application, créé avec configureStore.

Reducers

Mises à jour pures

Des fonctions qui prennent l'état actuel et une action pour retourner le nouvel état.

Actions

Événements

De simples objets décrivant ce qui s'est passé, dispatchés depuis les composants et gérés dans les reducers.

Redux Toolkit en un coup d'œil

Le cœur de Toolkit

configureStore

Crée le store avec des configurations par défaut pertinentes et les devtools activés.

createSlice

Génère les actions et les reducers pour une fonctionnalité dans un seul fichier.

useSelector

Lit une partie de l'état et ne déclenche un re-render que lorsque cette partie change.

useDispatch

Envoie des actions depuis les composants pour mettre à jour le store.

createAsyncThunk

Gère les tâches asynchrones avec des états pending, fulfilled et rejected.

RTK Query

Une couche intégrée de récupération et de mise en cache des données pour l'état serveur.

Un bref aperçu

Du boilerplate au "batteries included"

  1. 2015

    Sortie de Redux

    Un conteneur d'état prévisible inspiré de Flux devient l'outil de gestion d'état par défaut pour React.

    15
  2. 2019

    Redux Toolkit

    Le package officiel élimine le boilerplate et ajoute Immer, les devtools et des configurations middleware par défaut.

    19
  3. 2021

    RTK Query

    Une couche de récupération et de mise en cache des données est ajoutée au toolkit.

    21
  4. 2022

    Standard recommandé

    Toolkit devient la seule manière recommandée d'écrire du Redux, les anciens patterns étant déconseillés.

    22
  5. Aujourd'hui

    Mature et stable

    Un choix fiable pour les grandes applications avec un état client complexe et partagé.

    Aujourd'hui

Le guide complet

Redux Toolkit: Tout ce que vous devez savoir

Qu’est-ce que Redux Toolkit ?

Redux est un conteneur d’état prévisible : un store unique détient l’état de votre application, et le seul moyen de le modifier est de dispatcher une action traitée par un reducer pur. C’est cette contrainte qui rend Redux puissant — chaque changement d’état est explicite, traçable et testable.

Pendant des années, Redux a également été célèbre pour son code répétitif (boilerplate). Redux Toolkit a corrigé cela. C’est aujourd’hui la méthode officielle et recommandée pour écrire du Redux, regroupant configureStore, createSlice, Immer pour les mises à jour immuables, le middleware thunk et les devtools dans un seul package. Vous bénéficiez ainsi de l’architecture sans la lourdeur administrative.

Le store et les slices

Une slice regroupe la logique du reducer et les actions d’une fonctionnalité en un seul endroit. configureStore combine les slices dans le store.

// app/store.js
import { configureStore } from "@reduxjs/toolkit";
import counterReducer from "../features/counter/counterSlice";
import todosReducer from "../features/todos/todosSlice";

export const store = configureStore({
  reducer: {
    counter: counterReducer,
    todos: todosReducer,
  },
});
// main.jsx
import { Provider } from "react-redux";
import { store } from "./app/store";

<Provider store={store}>
  <App />
</Provider>;

createSlice génère pour vous les action creators et le reducer, vous n’avez donc jamais besoin d’écrire manuellement des constantes de type d’action. Immer propulse les reducers, ce qui signifie que vous pouvez écrire du code qui ressemble à une mutation alors que l’état reste immuable.

// features/todos/todosSlice.js
import { createSlice } from "@reduxjs/toolkit";

const todosSlice = createSlice({
  name: "todos",
  initialState: [],
  reducers: {
    add(state, action) {
      state.push(action.payload);
    },
    toggle(state, action) {
      const todo = state.find((t) => t.id === action.payload);
      if (todo) todo.done = !todo.done;
    },
    remove(state, action) {
      return state.filter((t) => t.id !== action.payload);
    },
  },
});

export const { add, toggle, remove } = todosSlice.actions;
export default todosSlice.reducer;

Lecture et dispatch

Les composants lisent l’état avec useSelector et envoient des actions avec useDispatch.

// TodoList.jsx
import { useSelector, useDispatch } from "react-redux";
import { add, toggle } from "../features/todos/todosSlice";

export function TodoList() {
  const todos = useSelector((state) => state.todos);
  const dispatch = useDispatch();

  return (
    <ul>
      {todos.map((todo) => (
        <li key={todo.id} onClick={() => dispatch(toggle(todo.id))}>
          {todo.done ? "✓" : "○"} {todo.text}
        </li>
      ))}
      <button onClick={() => dispatch(add({ id: 1, text: "New" }))}>
        Add
      </button>
    </ul>
  );
}

Sélectionnez la plus petite tranche (slice) possible. useSelector provoque le re-rendu du composant lorsque la valeur sélectionnée change ; sélectionner l’intégralité de l’état annulerait donc l’optimisation. Utilisez createSelector de Reselect lorsqu’une valeur dérivée risquerait d’être recalculée à chaque rendu.

Logique asynchrone avec les thunks

createAsyncThunk génère les trois types d’actions produits par une requête asynchrone, que vous gérez ensuite dans extraReducers.

// features/users/usersSlice.js
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";

export const fetchUsers = createAsyncThunk("users/fetch", async () => {
  const res = await fetch("/api/users");
  if (!res.ok) throw new Error("Failed to fetch users");
  return res.json();
});

const usersSlice = createSlice({
  name: "users",
  initialState: { items: [], status: "idle", error: null },
  reducers: {},
  extraReducers: (builder) => {
    builder
      .addCase(fetchUsers.pending, (state) => {
        state.status = "loading";
      })
      .addCase(fetchUsers.fulfilled, (state, action) => {
        state.status = "succeeded";
        state.items = action.payload;
      })
      .addCase(fetchUsers.rejected, (state, action) => {
        state.status = "failed";
        state.error = action.error.message;
      });
  },
});

C’est le pattern Redux explicite : le chargement (loading), le succès (success) et l’échec (failure) sont tous des actions que vous pouvez inspecter dans les devtools.

RTK Query pour l’état du serveur

Pour la récupération de données, RTK Query supprime complètement les thunks. Vous définissez un slice d’API avec des endpoints, et il gère le caching, la déduplication, l’invalidation et le refetching.

// features/api/apiSlice.js
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";

export const api = createApi({
  reducerPath: "api",
  baseQuery: fetchBaseQuery({ baseUrl: "/api" }),
  tagTypes: ["Post"],
  endpoints: (builder) => ({
    getPosts: builder.query({ query: () => "posts", providesTags: ["Post"] }),
    addPost: builder.mutation({
      query: (body) => ({ url: "posts", method: "POST", body }),
      invalidatesTags: ["Post"],
    }),
  }),
});

export const { useGetPostsQuery, useAddPostMutation } = api;
// Posts.jsx
const { data, isLoading, error } = useGetPostsQuery();

RTK Query est la réponse de Redux à TanStack Query : conserver l’état du serveur dans un cache avec un cycle de vie, et conserver l’état du client dans des slices. C’est en mélangeant ces deux responsabilités au même endroit que les applications Redux deviennent confuses.

Middleware et devtools

configureStore active l’extension Redux DevTools et inclut le middleware thunk par défaut. Vous pouvez ajouter vos propres middlewares pour le logging, l’analyse ou les effets de bord.

// middleware.js
const logger = (store) => (next) => (action) => {
  console.log("dispatching", action.type);
  return next(action);
};

export const store = configureStore({
  reducer: rootReducer,
  middleware: (getDefault) => getDefault().concat(logger),
});

Les devtools vous permettent d’inspecter chaque action dispatchée, de comparer l’état avant et après, et de rejouer l’historique — c’est la raison principale pour laquelle les équipes choisissent Redux pour la gestion d’états complexes.

Bonnes pratiques

  • Utilisez Redux Toolkit, ne rédigez jamais Redux à la main.
  • Maintenez un seul slice par fonctionnalité et regroupez la logique associée.
  • Sélectionnez la plus petite partie possible de l’état dans useSelector.
  • Utilisez createSelector pour les données dérivées dont le calcul est coûteux.
  • Gérez l’état du serveur avec RTK Query, et non dans des slices.
  • Ne stockez que des données sérialisables ; gardez les valeurs non sérialisables en dehors du store.
  • Modélisez les actions comme des événements qui se sont produits, et non comme des setters.

Erreurs courantes

  • Sélectionner l’intégralité du state et déclencher un re-render à chaque modification.
  • Placer des données serveur dans des slices et gérer manuellement les indicateurs de chargement (loading flags).
  • Stocker des valeurs non sérialisables, comme des instances de classe ou des fonctions.
  • Muter le state en dehors d’un reducer.
  • Utiliser Redux pour un état local de composant que useState pourrait gérer.
  • Écrire du code Redux legacy verbeux au lieu d’utiliser des slices.

Et après ?

Redux Toolkit est le choix mature pour gérer des états clients larges et complexes. Comparez-le avec l’ Context API native de React et la solution plus légère Zustand, et déléguez la gestion du serveur à TanStack Query ou RTK Query. Pour Vue, c’est Pinia qui remplit ce rôle.

Écrire un reducer

createSlice génère les action creators et utilise Immer pour vous permettre d'écrire du code qui semble muter tout en restant immuable.

Toolkit
const slice = createSlice({
  name: "todos",
  initialState: [],
  reducers: {
    add(state, action) {
      state.push(action.payload);
    },
  },
});
Legacy Redux
function todos(state = [], action) {
  switch (action.type) {
    case "todos/add":
      return [...state, action.payload];
    default:
      return state;
  }
}
// plus action creators,
// constants and types

Lire l'état

Sélectionnez la plus petite slice possible pour que le composant ne se re-render que lorsque cette valeur change.

Préférer
const count = useSelector(
  (state) => state.counter.value,
);
Éviter
const state = useSelector(
  (state) => state,
);
// re-renders on any change

FAQ

Foire aux questions

Keep learning

Related topics from the roadmap.

$ commencer à apprendre

Prêt à apprendre Redux Toolkit ?

Notre tutoriel interactif vous guide à travers Redux Toolkit pas à pas — avec des quiz et du vrai code que vous pouvez exécuter dans le navigateur.