Predictable State

Redux Toolkit

Redux Toolkit es la forma moderna y oficial de escribir Redux. Elimina el código repetitivo, incluye Immer para actualizaciones inmutables e integra devtools, middleware y 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;
Basado en
Redux
Inmutabilidad
Immer, integrado
Configuración del store
configureStore
Lógica
createSlice
Async
createAsyncThunk, RTK Query
Devtools
Habilitadas por defecto

Por que importa

Por qué Redux sigue siendo relevante

Predecible por diseño

Los cambios de estado ocurren solo a través de acciones y reducers puros, por lo que cada transición es rastreable y testeable.

Devtools con viaje en el tiempo

Inspecciona cada acción, compara el estado y reproduce el historial, lo que hace que los bugs difíciles sean reproducibles.

Baterías incluidas

Immer, middleware, devtools y una capa de obtención de datos vienen integrados, reduciendo drásticamente la configuración manual.

La imagen completa

Las tres ideas detrás de Redux

Un único store, reducers puros y acciones despachadas. Toolkit mantiene las ideas y elimina la ceremonia.

El store

Fuente única

Un único objeto contiene el estado de la aplicación, creado con configureStore.

Reducers

Actualizaciones puras

Funciones que toman el estado actual y una acción, y devuelven el siguiente estado.

Actions

Eventos

Objetos simples que describen qué sucedió, despachados desde los componentes y manejados en los reducers.

Redux Toolkit de un vistazo

El núcleo de Toolkit

configureStore

Crea el store con valores predeterminados sensatos y las devtools habilitadas.

createSlice

Genera acciones y reducers para una funcionalidad en un solo archivo.

useSelector

Lee una parte del estado y provoca un re-renderizado solo cuando esa parte cambia.

useDispatch

Envía acciones desde los componentes para actualizar el store.

createAsyncThunk

Maneja tareas asíncronas con estados de pending, fulfilled y rejected.

RTK Query

Una capa integrada de obtención de datos y almacenamiento en caché para el estado del servidor.

Una breve historia

Del boilerplate a las baterías incluidas

  1. 2015

    Lanzamiento de Redux

    Un contenedor de estado predecible inspirado en Flux se convierte en la herramienta de estado predeterminada para React.

    15
  2. 2019

    Redux Toolkit

    El paquete oficial elimina el boilerplate y añade Immer, devtools y configuraciones predeterminadas de middleware.

    19
  3. 2021

    RTK Query

    Se añade al toolkit una capa de obtención de datos y almacenamiento en caché.

    21
  4. 2022

    Estándar recomendado

    Toolkit se convierte en la única forma recomendada de escribir Redux, desaconsejando los patrones antiguos.

    22
  5. Hoy

    Maduro y estable

    Una opción fiable para aplicaciones grandes con un estado de cliente complejo y compartido.

    Hoy

La guia completa

Redux Toolkit: Todo lo que necesitas saber

¿Qué es Redux Toolkit?

Redux es un contenedor de estado predecible: un único store almacena el estado de tu aplicación, y la única forma de cambiarlo es despachando una acción que un reducer puro procesa. Esa restricción es lo que hace que Redux sea potente: cada cambio de estado es explícito, rastreable y testeable.

Durante años, Redux también fue famoso por su boilerplate. Redux Toolkit solucionó eso. Es la forma oficial y recomendada de escribir Redux hoy en día, agrupando configureStore, createSlice, Immer para actualizaciones inmutables, thunk middleware y devtools en un solo paquete. Obtienes la arquitectura sin toda la ceremonia.

El store y los slices

Un slice es la lógica del reducer y las acciones de una funcionalidad concentradas en un solo lugar. configureStore combina los slices en el 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 genera los action creators y el reducer por ti, para que nunca tengas que escribir a mano las constantes de los tipos de acción. Immer potencia los reducers, lo que significa que puedes escribir código que parece una mutación mientras el estado permanece inmutable.

// 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;

Lectura y despacho

Los componentes leen el estado con useSelector y envían acciones con 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>
  );
}

Selecciona la porción más pequeña que necesites. useSelector vuelve a renderizar el componente cuando el valor seleccionado cambia, por lo que seleccionar todo el estado anularía la optimización. Utiliza createSelector de Reselect cuando un valor derivado se recalcularía en cada renderizado.

Lógica asíncrona con thunks

createAsyncThunk genera los tres tipos de acciones que produce una solicitud asíncrona, los cuales manejas en 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;
      });
  },
});

Este es el patrón explícito de Redux: el estado de carga (loading), el éxito (success) y el fallo (failure) son acciones que puedes inspeccionar en las devtools.

RTK Query para el estado del servidor

Para la obtención de datos, RTK Query elimina por completo los thunks. Defines un API slice con endpoints, y este se encarga del caching, la deduplicación, la invalidación y el 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 es la respuesta de Redux a TanStack Query: mantener el estado del servidor en un cache con un ciclo de vida, y mantener el estado del cliente en slices. Mezclar ambas responsabilidades en un mismo lugar es lo que hace que las aplicaciones de Redux se vuelvan caóticas.

Middleware y devtools

configureStore habilita la extensión Redux DevTools e incluye el middleware thunk por defecto. Puedes añadir tu propio middleware para logging, analíticas o efectos secundarios.

// 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),
});

Las devtools te permiten inspeccionar cada acción despachada, comparar el estado antes y después, y reproducir el historial — la razón principal por la cual los equipos eligen Redux para estados complejos.

Mejores prácticas

  • Usa Redux Toolkit; nunca escribas Redux a mano.
  • Mantén un slice por funcionalidad y agrupa la lógica relacionada.
  • Selecciona la parte más pequeña posible del estado en useSelector.
  • Usa createSelector para datos derivados que requieran un cómputo costoso.
  • Mantén el estado del servidor en RTK Query, no en slices.
  • Almacena únicamente datos serializables; mantén los valores no serializables fuera del store.
  • Modela las acciones como eventos que ya ocurrieron, no como setters.

Errores comunes

  • Seleccionar todo el estado y provocar un re-renderizado en cada cambio.
  • Colocar datos del servidor en slices y gestionar los flags de carga manualmente.
  • Almacenar valores no serializables, como instancias de clases o funciones.
  • Mutar el estado fuera de un reducer.
  • Usar Redux para el estado local de un componente que useState podría manejar.
  • Escribir Redux legacy verboso en lugar de utilizar slices.

Próximos pasos

Redux Toolkit es la opción más madura para manejar estados de cliente grandes y complejos. Compáralo con la Context API integrada de React y con el más ligero Zustand, y delega las responsabilidades del servidor a TanStack Query o RTK Query. Para Vue, el rol equivalente lo cumple Pinia.

Escribir un reducer

createSlice genera los creadores de acciones y utiliza Immer para que puedas escribir código que parece mutar el estado, pero que permanece inmutable.

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

Leer el estado

Selecciona la parte más pequeña del estado que necesites para que el componente solo se renderice cuando ese valor cambie.

Preferido
const count = useSelector(
  (state) => state.counter.value,
);
Evitar
const state = useSelector(
  (state) => state,
);
// re-renders on any change

Preguntas frecuentes

Preguntas frecuentes

Keep learning

Related topics from the roadmap.

$ comienza a aprender

Listo para aprender Redux Toolkit?

Nuestro tutorial interactivo te guia a traves de Redux Toolkit paso a paso — con quizzes y codigo real que puedes ejecutar en el navegador.