Zustand vs Redux Toolkit: gerenciamento de estado que não te odeia
1. O Problema do Estado Global: Por Que a Dor Existe?
Gerenciar estado global em aplicações React sempre foi um campo minado. Durante anos, desenvolvedores aceitaram que lidar com estado centralizado significava enfrentar boilerplate interminável, configurações complexas e uma curva de aprendizado íngreme. O problema não era a ideia de ter um estado global — era como as ferramentas existentes nos obrigavam a implementá-lo.
Em projetos pequenos e médios, a complexidade desnecessária se torna rapidamente um fardo. Você começa com um contador simples e, de repente, está criando actions, reducers, constantes e conectando componentes com mapStateToProps. O trade-off histórico entre boilerplate e produtividade sempre pendia para o lado da burocracia.
O estado global deveria ser uma solução, não mais um problema. Felizmente, o ecossistema React evoluiu, e hoje temos duas abordagens que prometem exatamente isso: Redux Toolkit e Zustand. Ambas nasceram da insatisfação com o status quo, mas seguem filosofias radicalmente diferentes.
2. Redux Toolkit: O Padrão Maduro e Opinionado
Redux Toolkit (RTK) é a resposta oficial da equipe Redux para os anos de reclamações sobre boilerplate. Ele não reinventa a roda — ele a simplifica drasticamente.
Com createSlice, você define estado, reducers e actions em um único bloco de código. O Immer integrado permite que você "mute" o estado diretamente, enquanto o RTK cuida da imutabilidade nos bastidores. Para operações assíncronas, createAsyncThunk elimina a necessidade de escrever action creators manualmente para cada estado (pending, fulfilled, rejected).
// Redux Toolkit - store configurado com slice
import { createSlice, configureStore, createAsyncThunk } from '@reduxjs/toolkit'
const fetchUser = createAsyncThunk('user/fetch', async (userId) => {
const response = await fetch(`/api/users/${userId}`)
return response.json()
})
const userSlice = createSlice({
name: 'user',
initialState: { data: null, loading: false },
reducers: {
updateName: (state, action) => {
state.data.name = action.payload // Immer permite "mutação"
}
},
extraReducers: (builder) => {
builder
.addCase(fetchUser.pending, (state) => { state.loading = true })
.addCase(fetchUser.fulfilled, (state, action) => {
state.loading = false
state.data = action.payload
})
}
})
const store = configureStore({ reducer: { user: userSlice.reducer } })
RTK Query eleva ainda mais o nível, gerenciando cache, polling e invalidação de dados de API de forma declarativa. É uma solução completa para quem precisa de previsibilidade em larga escala.
3. Zustand: Minimalismo que Abraça a Simplicidade
Zustand (alemão para "estado") é a antítese do pensamento opinionado. Sua filosofia é simples: você não precisa de um provider, não precisa de contexto extra, não precisa de dezenas de arquivos. Uma store é um hook.
// Zustand - store completa em poucas linhas
import { create } from 'zustand'
const useStore = create((set, get) => ({
count: 0,
user: null,
loading: false,
increment: () => set((state) => ({ count: state.count + 1 })),
fetchUser: async (userId) => {
set({ loading: true })
const response = await fetch(`/api/users/${userId}`)
const data = await response.json()
set({ user: data, loading: false })
},
updateNestedField: (path, value) => {
const current = get()
// Lógica para atualização aninhada
set({ ...current, [path]: value })
}
}))
A API enxuta — create, set, get — é tudo que você precisa. Middleware como persist, immer e devtools são plugins opcionais que se integram sem configurar boilerplate. Não há contexto, não há providers aninhados, não há ceremony.
4. Comparação Prática: Código Lado a Lado
Vamos comparar uma lista de tarefas simples em ambas as ferramentas.
Redux Toolkit:
const todoSlice = createSlice({
name: 'todos',
initialState: { items: [], filter: 'all' },
reducers: {
addTodo: (state, action) => {
state.items.push({ id: Date.now(), text: action.payload, done: false })
},
toggleTodo: (state, action) => {
const todo = state.items.find(t => t.id === action.payload)
if (todo) todo.done = !todo.done
},
setFilter: (state, action) => { state.filter = action.payload }
}
})
// Componente precisa usar useDispatch e useSelector
Zustand:
const useTodoStore = create((set) => ({
items: [],
filter: 'all',
addTodo: (text) => set((state) => ({
items: [...state.items, { id: Date.now(), text, done: false }]
})),
toggleTodo: (id) => set((state) => ({
items: state.items.map(t => t.id === id ? { ...t, done: !t.done } : t)
})),
setFilter: (filter) => set({ filter })
}))
// Componente usa o hook diretamente: const { items, addTodo } = useTodoStore()
Para estado assíncrono, ambos lidam bem, mas Zustand ganha em simplicidade para casos simples. RTK Query é superior para cenários complexos de cache e polling.
Em atualizações aninhadas, o Immer do RTK brilha — você pode modificar objetos profundos sem espalhar operadores. Zustand exige mais cuidado manual, mas o middleware immer resolve isso.
5. Performance e Bundle Size: Quem Pesa Menos?
Os números não mentem. Redux Toolkit pesa aproximadamente 11KB (gzip), enquanto Zustand fica em torno de 1KB (gzip). Para aplicações onde cada kilobyte importa — como Progressive Web Apps ou sites mobile — Zustand é imbatível.
Em termos de re-renderizações, RTK oferece seletores memoizados com createSelector do Reselect, permitindo controle refinado. Zustand, por padrão, evita re-renderizações desnecessárias ao comparar referências dos valores retornados pelo seletor.
Para debugging, o ecossistema Redux é mais maduro: Redux DevTools são padrão da indústria. Zustand também suporta DevTools via middleware, mas a experiência não é tão rica.
6. Casos de Uso: Quando Escolher Cada Um?
Zustand ganha de lavada em:
- Projetos pequenos e médios (startups, MVPs, ferramentas internas)
- Micro-frontends e estados isolados por módulo
- Aplicações que priorizam bundle size mínimo
- Times pequenos que valorizam produtividade imediata
Redux Toolkit brilha em:
- Grandes aplicações com múltiplos times e dezenas de desenvolvedores
- Cenários que exigem middleware complexo (logging, analytics, sagas)
- Aplicações com estado altamente compartilhado entre domínios distantes
- Projetos que já usam Redux clássico e querem migrar gradualmente
7. Migração e Convivência: Os Dois Podem Coexistir?
Sim, e isso é um dos pontos fortes de ambas as bibliotecas. Você pode usar Zustand para estado de UI (modais, temas, sidebar) enquanto mantém Redux Toolkit para dados de domínio (usuários, produtos, pedidos).
// Coexistência pacífica
import { useDispatch } from 'react-redux'
import { useUIStore } from './stores/uiStore'
function Component() {
const dispatch = useDispatch()
const { theme, toggleSidebar } = useUIStore()
// Redux para dados de domínio
const handleSave = () => dispatch(saveUserData())
// Zustand para estado de UI
const handleToggle = () => toggleSidebar()
}
Estratégias de migração gradual incluem: começar novos recursos com Zustand, mover estado de UI do Redux para Zustand, ou usar Zustand como camada de cache local enquanto RTK Query gerencia o servidor.
8. Conclusão: A Escolha que Não Te Odeia
| Característica | Redux Toolkit | Zustand |
|---|---|---|
| Bundle size (gzip) | ~11KB | ~1KB |
| Curva de aprendizado | Moderada | Baixa |
| Boilerplate | Baixo (para RTK) | Mínimo |
| Ecossistema | Maduro | Crescente |
| Ideal para | Grandes apps, times grandes | Projetos médios, MVPs |
| Debugging | DevTools nativos | DevTools via middleware |
A escolha final depende do fator humano: a familiaridade da sua equipe, a complexidade do projeto e a necessidade de previsibilidade vs. velocidade. Minha recomendação pessoal: comece com Zustand. Ele resolve 80% dos problemas de estado com 20% do esforço. Quando você sentir dor — quando precisar de middleware complexo, cache sofisticado ou rastreamento de ações impecável — evolua para Redux Toolkit.
O importante é que nenhuma das duas ferramentas te odeia. Ambas foram criadas por desenvolvedores que sentiram sua dor e decidiram fazer algo a respeito. Escolha a que faz seu time mais feliz e produtivo.
Referências
- Documentação oficial do Redux Toolkit — Guia completo com tutoriais, exemplos e API reference para RTK, incluindo createSlice, createAsyncThunk e RTK Query.
- Documentação oficial do Zustand — Repositório oficial com exemplos práticos, middleware disponível e guia de migração.
- Redux Toolkit vs Zustand: Comparação Técnica Detalhada — Artigo de Robin Wieruch comparando performance, bundle size e casos de uso reais.
- Zustand: O Gerenciamento de Estado Minimalista para React — Tutorial do LogRocket cobrindo desde a instalação até padrões avançados com Zustand.
- Redux Toolkit: A Maneira Moderna de Escrever Redux — Curso em vídeo do Egghead.io ensinando RTK do zero com TypeScript.
- Comparação de Bundle Size: RTK vs Zustand vs Jotai — Ferramenta BundlePhobia para verificar o tamanho real de cada biblioteca e seu impacto no bundle final.