Zustand: A Maneira Leve e Descomplicada de Gerenciar Estado no React

O gerenciamento de estado é uma das pedras angulares do desenvolvimento de aplicações React. À medida que seus projetos crescem, a complexidade de compartilhar e atualizar dados entre componentes pode rapidamente se tornar um desafio. Frameworks robustos como Redux oferecem soluções completas, mas muitas vezes vêm com uma curva de aprendizado íngreme e um excesso de "boilerplate" para casos de uso mais simples. É aí que o Zustand entra em cena.

Se você busca uma solução de gerenciamento de estado que seja simples, rápida e sem complicação, este artigo é para você. Vamos mergulhar no mundo do Zustand e descobrir como ele pode simplificar sua vida como desenvolvedor React.

Introdução: Desafios do Gerenciamento de Estado no React

No coração de toda aplicação React, o estado define o que sua interface de usuário exibe e como ela se comporta. Gerenciar esse estado de forma eficaz é crucial para a manutenibilidade e escalabilidade da sua aplicação. O React nos oferece o Context API e os hooks useState/useReducer, que são ótimos para gerenciar o estado local ou para compartilhar estado em árvores de componentes menores.

No entanto, para o estado global ou para cenários onde o Context API pode levar a re-renderizações excessivas ou a um "prop drilling" (passagem de props por vários níveis), precisamos de algo mais. É nesse ponto que soluções de terceiros brilham, e o Zustand se destaca por sua filosofia minimalista.

"Zustand é uma solução de gerenciamento de estado pequena, rápida e escalável, com uma API simples e direta baseada em hooks."

O Que é Zustand?

Zustand é uma biblioteca de gerenciamento de estado que foi projetada para ser o mais simples e direto possível. "Zustand" significa "estado" em alemão, e a biblioteca vive de acordo com seu nome, focando em fornecer uma maneira intuitiva de gerenciar o estado global sem o peso de outras soluções.

Pequeno, Rápido e Escalável

  • Pequeno: Seu tamanho de bundle é minúsculo, o que significa que adiciona pouquíssimo peso à sua aplicação.

  • Rápido: Projetado para re-renderizações otimizadas, garantindo que apenas os componentes que realmente precisam ser atualizados sejam re-renderizados.

  • Escalável: Embora seja simples, o Zustand é poderoso o suficiente para lidar com aplicações complexas, oferecendo recursos como middleware e persistência.

A principal diferença do Zustand em relação a outras bibliotecas é sua abordagem "sem contexto". Ele não usa o Context API do React para injetar o estado, o que elimina alguns dos problemas de desempenho e complexidade associados a ele, especialmente em árvores de componentes grandes.

Por Que Escolher Zustand?

Existem várias razões pelas quais o Zustand pode ser a escolha perfeita para o seu próximo projeto React:

  • Simplicidade Inigualável: A API é incrivelmente fácil de aprender e usar. Se você já usa hooks do React, você se sentirá em casa.

  • Sem Boilerplate: Diga adeus a actions, reducers, sagas ou selectors complexos. Com Zustand, você define sua store e a usa. Simples assim.

  • Tamanho Mínimo: Com um bundle size de apenas alguns KB, ele não vai inchar sua aplicação.

  • Otimizado para Desempenho: Zustand utiliza seletores para garantir que seus componentes sejam re-renderizados apenas quando as partes do estado que eles consomem realmente mudam.

  • Flexibilidade: Pode ser usado com ou sem React, o que o torna uma ótima opção para compartilhar lógica de estado em diferentes partes da sua aplicação, ou até mesmo fora do ambiente React.

  • Suporte a TypeScript: Possui excelente suporte a TypeScript, garantindo tipos seguros para seu estado e ações.

Primeiros Passos com Zustand

Vamos criar um exemplo prático para ver como o Zustand funciona. Iremos construir um contador simples.

Instalação

Primeiro, instale o Zustand em seu projeto React:

npm install zustand

Ou, se você usa Yarn:

yarn add zustand

Criando sua Primeira Store

Uma "store" no Zustand é essencialmente um hook que você cria para gerenciar uma fatia do seu estado global. Crie um arquivo, por exemplo, src/store/useCounterStore.js:

import { create } from 'zustand';

const useCounterStore = create((set) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 })),
  decrement: () => set((state) => ({ count: state.count - 1 })),
  reset: () => set({ count: 0 }),
}));

export default useCounterStore;

Neste código:

  • create é a função principal do Zustand para criar uma store.

  • Ela recebe uma função que retorna um objeto. Este objeto define o estado inicial (count: 0) e as funções para modificá-lo (increment, decrement, reset).

  • A função set é fornecida pelo Zustand e permite atualizar o estado. Você pode passar um objeto diretamente (como em reset) ou uma função que recebe o estado atual e retorna um novo objeto de estado (como em increment e decrement), o que é recomendado para atualizações baseadas no estado anterior.

Usando a Store em um Componente

Agora, vamos usar essa store em um componente React, por exemplo, src/components/Counter.js:

import React from 'react';
import useCounterStore from '../store/useCounterStore';

function Counter() {
  const { count, increment, decrement, reset } = useCounterStore();

  return (
    <div>
      <h2>Meu Contador Zustand</h2>
      <p>Contagem: <strong>{count}</strong></p>
      <button onClick={increment}>Incrementar</button>
      <button onClick={decrement}>Decrementar</button>
      <button onClick={reset}>Resetar</button>
    </div>
  );
}

export default Counter;

E então, no seu App.js:

import React from 'react';
import Counter from './components/Counter';

function App() {
  return (
    <div className="App">
      <h1>Aplicação com Zustand</h1>
      <Counter />
    </div>
  );
}

export default App;

Você pode ver como é simples! Basta importar o hook da sua store e desestruturar as partes do estado e as ações que você precisa. O Zustand garante que seu componente será re-renderizado apenas quando count, increment, decrement ou reset mudarem (ou seja, quando o estado que ele está usando mudar).

Atualizando o Estado

A atualização do estado é feita através das funções que você define na sua store (increment, decrement, reset). Essas funções chamam a função set fornecida pelo Zustand para modificar o estado da store. É uma abordagem muito direta e intuitiva.

Recursos Avançados (Brevemente)

Embora o Zustand seja conhecido por sua simplicidade, ele também oferece recursos poderosos para lidar com cenários mais complexos:

Ações Assíncronas

Você pode facilmente lidar com ações assíncronas (como chamadas de API) dentro de suas funções de store. Basta usar async/await e chamar set quando os dados estiverem prontos:

import { create } from 'zustand';

const useUserStore = create((set) => ({
  user: null,
  loading: false,
  fetchUser: async (id) => {
    set({ loading: true });
    try {
      const response = await fetch(`https://api.example.com/users/${id}`);
      const data = await response.json();
      set({ user: data, loading: false });
    } catch (error) {
      console.error('Failed to fetch user', error);
      set({ loading: false });
    }
  },
}));

Middleware (Persistência, Devtools)

Zustand suporta middleware, permitindo estender a funcionalidade da sua store. Dois dos mais populares são:

  • persist: Para persistir seu estado no localStorage ou sessionStorage, mantendo-o mesmo após o usuário fechar o navegador.

  • devtools: Para integrar sua store com as Redux DevTools, facilitando a depuração.

import { create } from 'zustand';
import { persist, devtools } from 'zustand/middleware';

const usePersistentStore = create(devtools(persist(
  (set) => ({
    items: [],
    addItem: (item) => set((state) => ({ items: [...state.items, item] })),
  }),
  {
    name: 'my-app-storage', // nome da key no localStorage
  }
)));

Seletores para Otimização

Para evitar re-renderizações desnecessárias, você pode selecionar apenas as partes do estado que um componente realmente precisa. Por exemplo, se você só precisa do count e não das funções increment ou decrement:

import React from 'react';
import useCounterStore from '../store/useCounterStore';

function DisplayCount() {
  const count = useCounterStore((state) => state.count);

  return (
    <div>
      <p>A contagem atual é: <strong>{count}</strong></p>
    </div>
  );
}

export default DisplayCount;

Neste caso, DisplayCount só será re-renderizado se state.count mudar, ignorando quaisquer outras mudanças na store.

Conclusão

O Zustand se estabelece como uma alternativa excelente e descomplicada para o gerenciamento de estado em aplicações React. Sua filosofia de "menos é mais", combinada com uma API intuitiva e hooks-friendly, o torna uma ferramenta poderosa para desenvolvedores que buscam eficiência e simplicidade.

Seja você um iniciante no React procurando uma maneira fácil de gerenciar o estado global, ou um desenvolvedor experiente cansado do boilerplate de outras soluções, o Zustand oferece uma abordagem leve e refrescante que vale a pena explorar.

Dê uma chance ao Zustand em seu próximo projeto. Você pode se surpreender com o quão fácil e agradável o gerenciamento de estado pode ser!