Predictable State

Redux Toolkit

Redux Toolkit é a maneira moderna e oficial de escrever Redux. Ele remove o boilerplate, inclui Immer para atualizações imutáveis e já vem com devtools, middleware e RTK Query.

intermediate15 min readUpdated 15 de set. de 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;
Construído sobre
Redux
Imutabilidade
Immer, integrado
Configuração da Store
configureStore
Lógica
createSlice
Async
createAsyncThunk, RTK Query
Devtools
Habilitado por padrão

Por que importa

Por que o Redux ainda mantém seu espaço

Previsível por design

As mudanças de estado ocorrem apenas através de actions e reducers puros, tornando cada transição rastreável e testável.

Devtools com time-travel

Inspecione cada action, compare a diferença de estado e reproduza o histórico, tornando bugs complexos reproduzíveis.

Batteries included

Immer, middleware, devtools e uma camada de busca de dados já vêm juntos, reduzindo drasticamente a quantidade de código de configuração.

O panorama completo

As três ideias por trás do Redux

Uma única store, reducers puros e actions disparadas. O Toolkit mantém as ideias e remove a cerimônia.

A store

Fonte única

Um único objeto detém o estado da aplicação, criado com configureStore.

Reducers

Atualizações puras

Funções que recebem o estado atual e uma action e retornam o próximo estado.

Actions

Eventos

Objetos simples que descrevem o que aconteceu, disparados por componentes e manipulados em reducers.

Redux Toolkit em resumo

O núcleo do Toolkit

configureStore

Cria a store com padrões sensatos e devtools habilitados.

createSlice

Gera actions e reducers para uma funcionalidade em um único arquivo.

useSelector

Lê uma fatia (slice) do estado e renderiza novamente apenas quando essa fatia muda.

useDispatch

Envia actions dos componentes para atualizar a store.

createAsyncThunk

Lida com tarefas assíncronas com estados de pending, fulfilled e rejected.

RTK Query

Uma camada integrada de busca de dados e cache para estado do servidor.

Uma breve historia

Do boilerplate ao 'batteries included'

  1. 2015

    Lançamento do Redux

    Um container de estado previsível inspirado no Flux torna-se a ferramenta padrão de estado para React.

    15
  2. 2019

    Redux Toolkit

    O pacote oficial remove o boilerplate e adiciona Immer, devtools e padrões de middleware.

    19
  3. 2021

    RTK Query

    Uma camada de busca de dados e cache é adicionada ao toolkit.

    21
  4. 2022

    Padrão recomendado

    O Toolkit torna-se a única maneira recomendada de escrever Redux, com padrões legados sendo desencorajados.

    22
  5. Hoje

    Maduro e estável

    Uma escolha confiável para aplicações grandes com estado de cliente complexo e compartilhado.

    Hoje

O guia completo

Redux Toolkit: Tudo que voce precisa saber

O que é Redux Toolkit?

Redux é um container de estado previsível: um único store armazena o estado da sua aplicação, e a única maneira de alterá-lo é disparando (dispatch) uma action que é processada por um reducer puro. Essa restrição é o que torna o Redux poderoso — cada mudança de estado é explícita, rastreável e testável.

Por anos, o Redux também foi famoso pelo excesso de boilerplate. O Redux Toolkit resolveu isso. Ele é a maneira oficial e recomendada de escrever Redux hoje em dia, reunindo configureStore, createSlice, Immer para atualizações imutáveis, thunk middleware e devtools em um único pacote. Você obtém a arquitetura sem a burocracia.

A store e os slices

Um slice reúne a lógica do reducer e as actions de uma funcionalidade em um só lugar. configureStore combina os slices na 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 gera os action creators e o reducer para você, eliminando a necessidade de escrever constantes de tipos de action manualmente. O Immer alimenta os reducers, o que significa que você pode escrever códigos que parecem mutações, enquanto o estado permanece imutável.

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

Leitura e despacho

Os componentes leem o estado com useSelector e enviam ações com 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>
  );
}

Selecione a menor fatia (slice) necessária. O useSelector renderiza novamente o componente quando o valor selecionado muda, portanto, selecionar todo o estado anula a otimização. Use createSelector do Reselect quando um valor derivado precisaria ser recalculado a cada renderização.

Lógica assíncrona com thunks

createAsyncThunk gera os três tipos de action que uma requisição assíncrona produz, os quais você manipula no 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 é o padrão explícito do Redux: loading, success e failure são todas actions que você pode inspecionar no devtools.

RTK Query para estado do servidor

Para a busca de dados, o RTK Query remove completamente a necessidade de thunks. Você define um API slice com endpoints, e ele gerencia o cache, a deduplicação, a invalidação e o 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();

O RTK Query é a resposta do Redux ao TanStack Query: mantenha o estado do servidor em um cache com ciclo de vida e mantenha o estado do cliente em slices. Misturar essas duas responsabilidades em um único lugar é o que torna as aplicações Redux confusas.

Middleware e devtools

configureStore habilita a extensão Redux DevTools e inclui o middleware thunk por padrão. Você pode adicionar seus próprios middlewares para logging, analytics ou side effects.

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

Os devtools permitem inspecionar cada action disparada, comparar a diferença do estado antes e depois, e reproduzir o histórico — o principal motivo pelo qual as equipes escolhem Redux para estados complexos.

Melhores práticas

  • Use Redux Toolkit, nunca Redux escrito manualmente.
  • Mantenha um slice por funcionalidade e agrupe a lógica relacionada.
  • Selecione a menor fatia de estado possível em useSelector.
  • Use createSelector para dados derivados que sejam caros para computar.
  • Mantenha o estado do servidor no RTK Query, não em slices.
  • Armazene apenas dados serializáveis; mantenha valores não serializáveis fora do store.
  • Modele as actions como eventos que aconteceram, não como setters.

Erros comuns

  • Selecionar todo o estado e disparar a re-renderização a cada alteração.
  • Colocar dados do servidor em slices e gerenciar flags de carregamento manualmente.
  • Armazenar valores não serializáveis, como instâncias de classes ou funções.
  • Mutar o estado fora de um reducer.
  • Usar Redux para estados locais de componentes que useState resolveria.
  • Escrever Redux legado e verboso em vez de utilizar slices.

Próximos passos

O Redux Toolkit é a escolha madura para estados de cliente grandes e complexos. Compare-o com a Context API nativa do React e com o mais leve Zustand, e separe as preocupações de servidor utilizando TanStack Query ou RTK Query. Para Vue, o papel equivalente é preenchido pelo Pinia.

Escrevendo um reducer

O createSlice gera action creators e usa Immer para que você possa escrever código que parece mutável, mas permanece imutável.

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

Lendo o estado

Selecione a menor fatia possível para que o componente renderize novamente apenas quando esse valor mudar.

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

Perguntas frequentes

Perguntas frequentes

Keep learning

Related topics from the roadmap.

$ comecar a aprender

Pronto para aprender Redux Toolkit?

Nosso tutorial interativo te guia por Redux Toolkit passo a passo — com quizzes e codigo real que voce pode executar no navegador.