JavaScript Avançado

Gerenciamento de Estado Avançado: Zustand, Jotai e Recoil Comparados na Prática

7 min de leitura

Gerenciamento de Estado Avançado: Zustand, Jotai e Recoil Comparados na Prática

Introdução ao Gerenciamento de Estado Moderno O gerenciamento de estado é um dos desafios centrais em aplicações React modernas. Ao longo dos anos, passamos de Redux—com toda sua verbosidade—para soluções mais minimalistas e intuitivas. Zustand, Jotai e Recoil representam essa evolução, cada uma com filosofias distintas. Neste artigo, exploraremos essas três bibliotecas, seus trade-offs e quando usá-las, para que você possa tomar decisões informadas em seus projetos. Zustand: Simplicidade e Minimalismo Zustand é uma biblioteca extremamente leve (2.9KB) que oferece uma API simples e direta. Sua filosofia é: "você não precisa de tanto código para gerenciar estado". A biblioteca usa Hooks do React nativamente e funciona sem providers, tornando-a ideal para projetos que valorizam simplicidade. Características principais Zustand armazena estado em uma store única (embora você possa criar múltiplas) e oferece seletores granulares para evitar re-renders desnecessários. O padrão é usar para definir sua store: O grande diferencial é a ausência de boilerplate. Você não precisa de reducers, actions ou

<h2>Introdução ao Gerenciamento de Estado Moderno</h2>

<p>O gerenciamento de estado é um dos desafios centrais em aplicações React modernas. Ao longo dos anos, passamos de Redux—com toda sua verbosidade—para soluções mais minimalistas e intuitivas. Zustand, Jotai e Recoil representam essa evolução, cada uma com filosofias distintas. Neste artigo, exploraremos essas três bibliotecas, seus trade-offs e quando usá-las, para que você possa tomar decisões informadas em seus projetos.</p>

<h2>Zustand: Simplicidade e Minimalismo</h2>

<p>Zustand é uma biblioteca extremamente leve (2.9KB) que oferece uma API simples e direta. Sua filosofia é: &quot;você não precisa de tanto código para gerenciar estado&quot;. A biblioteca usa Hooks do React nativamente e funciona sem providers, tornando-a ideal para projetos que valorizam simplicidade.</p>

<h3>Características principais</h3>

<p>Zustand armazena estado em uma store única (embora você possa criar múltiplas) e oferece seletores granulares para evitar re-renders desnecessários. O padrão é usar <code>create</code> para definir sua store:</p>

<pre><code class="language-javascript">import create from &#039;zustand&#039;;

const useCounterStore = create((set) =&gt; ({

count: 0,

increment: () =&gt; set((state) =&gt; ({ count: state.count + 1 })),

decrement: () =&gt; set((state) =&gt; ({ count: state.count - 1 })),

reset: () =&gt; set({ count: 0 }),

}));

// Uso em componente

function Counter() {

const count = useCounterStore((state) =&gt; state.count);

const increment = useCounterStore((state) =&gt; state.increment);

return (

&lt;div&gt;

&lt;p&gt;Count: {count}&lt;/p&gt;

&lt;button onClick={increment}&gt;+1&lt;/button&gt;

&lt;/div&gt;

);

}</code></pre>

<p>O grande diferencial é a ausência de boilerplate. Você não precisa de reducers, actions ou dispatches—apenas uma função que retorna seu estado e seus métodos. Para estado mais complexo, Zustand ainda mantém a elegância:</p>

<pre><code class="language-javascript">const useAppStore = create((set) =&gt; ({

user: null,

todos: [],

setUser: (user) =&gt; set({ user }),

addTodo: (todo) =&gt; set((state) =&gt; ({

todos: [...state.todos, todo],

})),

loading: false,

setLoading: (bool) =&gt; set({ loading: bool }),

}));</code></pre>

<h2>Jotai: Abordagem Atômica e Composável</h2>

<p>Jotai (que significa &quot;estado&quot; em japonês) traz uma perspectiva diferente: em vez de uma store centralizada, você trabalha com átomos—unidades isoladas de estado. Isso permite composição granular e é especialmente poderoso em aplicações complexas onde diferentes partes precisam de estados independentes mas relacionados.</p>

<h3>Arquitetura e uso</h3>

<p>Jotai separa lógica de estado da lógica de componentes através de átomos primitivos:</p>

<pre><code class="language-javascript">import { atom, useAtom, useAtomValue, useSetAtom } from &#039;jotai&#039;;

const countAtom = atom(0);

const nameAtom = atom(&#039;John&#039;);

// Átomos derivados (computed atoms)

const greetingAtom = atom((get) =&gt; {

const count = get(countAtom);

const name = get(nameAtom);

return Hello ${name}, you have ${count} items;

});

function Component() {

const [count, setCount] = useAtom(countAtom);

const greeting = useAtomValue(greetingAtom);

const setName = useSetAtom(nameAtom);

return (

&lt;div&gt;

&lt;p&gt;{greeting}&lt;/p&gt;

&lt;button onClick={() =&gt; setCount(count + 1)}&gt;Increment&lt;/button&gt;

&lt;button onClick={() =&gt; setName(&#039;Alice&#039;)}&gt;Change Name&lt;/button&gt;

&lt;/div&gt;

);

}</code></pre>

<p>A vantagem aqui é a reatividade natural: átomos derivados atualizam automaticamente quando suas dependências mudam. Jotai também suporta async atoms nativamente, ideal para requisições de API:</p>

<pre><code class="language-javascript">const userAtom = atom(

async (get) =&gt; {

const response = await fetch(&#039;/api/user&#039;);

return response.json();

}

);

function UserProfile() {

const user = useAtomValue(userAtom);

if (!user) return &lt;p&gt;Loading...&lt;/p&gt;;

return &lt;p&gt;User: {user.name}&lt;/p&gt;;

}</code></pre>

<h2>Recoil: Reatividade Profunda e DevTools</h2>

<p>Recoil, desenvolvido pelo Facebook, é a solução mais sofisticada das três. Oferece um sistema reativo completo com selectors, efeitos colaterais (effects) e ferramentas avançadas de debug. É ideal quando você precisa de estado altamente reativo com dependências complexas.</p>

<h3>Estrutura e padrões</h3>

<p>Recoil funciona com átomos e selectors, mas adiciona camadas de funcionalidade como efeitos e validação:</p>

<pre><code class="language-javascript">import { atom, selector, useRecoilState, useRecoilValue } from &#039;recoil&#039;;

const userIdAtom = atom({

key: &#039;userId&#039;,

default: null,

});

const userSelector = selector({

key: &#039;user&#039;,

get: async ({ get }) =&gt; {

const userId = get(userIdAtom);

if (!userId) return null;

const response = await fetch(/api/users/${userId});

return response.json();

},

});

function UserDetail() {

const userId = useRecoilState(userIdAtom);

const user = useRecoilValue(userSelector);

return &lt;div&gt;{user?.name}&lt;/div&gt;;

}</code></pre>

<p>Recoil também permite effects para sincronização com localStorage ou APIs:</p>

<pre><code class="language-javascript">const persistedCountAtom = atom({

key: &#039;persistedCount&#039;,

default: 0,

effects: [

({ setSelf, onSet }) =&gt; {

// Carregar do localStorage ao inicializar

setSelf(localStorage.getItem(&#039;count&#039;) ?? 0);

// Salvar quando mudar

onSet((newValue) =&gt; {

localStorage.setItem(&#039;count&#039;, newValue);

});

},

],

});</code></pre>

<h2>Comparação Prática</h2>

<blockquote><p><strong>Zustand</strong> vence em simplicidade e tamanho. Use quando você quer estado gerenciado sem complexidade.</p></blockquote>

<blockquote><p><strong>Jotai</strong> é superior para composição e múltiplas unidades de estado independentes. Melhor para microfrontends.</p></blockquote>

<blockquote><p><strong>Recoil</strong> é mais poderoso para dependências complexas e async, com melhor DevTools.</p></blockquote>

<p>Uma tabela mental: Zustand = Redux simplificado. Jotai = estado atômico. Recoil = reatividade total.</p>

<h2>Conclusão</h2>

<p>Aprendemos que não existe &quot;melhor&quot; biblioteca—existe a mais adequada para seu contexto. <strong>Zustand</strong> é sua escolha se simplicidade é prioridade e seu estado é relativamente plano. <strong>Jotai</strong> brilha em aplicações modernas com muitos pedaços de estado independentes e composição. <strong>Recoil</strong> é a escolha para aplicações complexas que exigem reatividade profunda e sincronização elegante.</p>

<p>Minha recomendação profissional: comece com Zustand para 80% dos projetos. Use Jotai se trabalha com múltiplos átomos independentes. Reserve Recoil para when you need advanced reactivity patterns and are willing to accept a larger bundle and slightly steeper learning curve.</p>

<h2>Referências</h2>

<ul>

<li><a href="https://github.com/pmndrs/zustand" target="_blank" rel="noopener noreferrer">Zustand Official Documentation</a></li>

<li><a href="https://jotai.org/" target="_blank" rel="noopener noreferrer">Jotai Documentation</a></li>

<li><a href="https://recoiljs.org/" target="_blank" rel="noopener noreferrer">Recoil Official Docs</a></li>

<li><a href="https://blog.logrocket.com/" target="_blank" rel="noopener noreferrer">React State Management Comparison - LogRocket</a></li>

<li><a href="https://kentcdodds.com/blog" target="_blank" rel="noopener noreferrer">State Management in React - Kent C. Dodds</a></li>

</ul>

Comentários

Mais em JavaScript Avançado

Como Usar Monorepo com TypeScript: Turborepo, Paths e Shared Packages em Produção
Como Usar Monorepo com TypeScript: Turborepo, Paths e Shared Packages em Produção

O que é Monorepo e por que usar Turborepo? Um monorepo é um repositório único...

Boas Práticas de Motor V8 por Dentro: Compilação JIT, Otimizações e Deoptimizações para Times Ágeis
Boas Práticas de Motor V8 por Dentro: Compilação JIT, Otimizações e Deoptimizações para Times Ágeis

Motor V8 por Dentro: Compilação JIT, Otimizações e Deoptimizações Introdução...

Dominando Fastify em Node.js: Alta Performance e Schema Validation com JSON Schema em Projetos Reais
Dominando Fastify em Node.js: Alta Performance e Schema Validation com JSON Schema em Projetos Reais

Por que Fastify? Fastify é um framework web moderno para Node.js que se desta...