R
Interview Deckreact · next.js · senior/staff
0·0·122
Estado Global

Jotai — Estado Atômico

Atoms independentes, estado derivado com atomFamily, e integração com React Suspense.

Jotai é um gerenciador de estado atômico: cada atom é um pedaço independente de estado. Diferente do Zustand (um store), Jotai é bottom-up — componentes se subscrevem a atoms específicos. Atoms derivados (computed): atom((get) => get(aAtom) + get(bAtom)). atomFamily para atoms dinâmicos por ID. Integração nativa com Suspense para async atoms.

Problema
Zustand/Redux com um store global: qualquer componente pode escrever qualquer parte do estado acidentalmente. Estado muito granular exige muitos seletores. Atoms async com loading state manual.
Solução
Jotai: cada atom é isolado. Componente só pode acessar atoms que importa explicitamente. Atom derivado é automaticamente memoizado. loadable() para async atoms sem Suspense. atomFamily para coleções (atom por ID de produto).
Tip
Jotai brilha para estado de UI muito granular e independente: abrir/fechar de N dropdowns, hover state de N items em lista, configurações por item. Onde Zustand tem um store centralizado, Jotai tem atoms distribuídos pelos componentes.
import { atom, useAtom, useAtomValue, useSetAtom } from 'jotai'
import { atomFamily, loadable } from 'jotai/utils'

// Atom primitivo
const countAtom = atom(0)

// Atom derivado (read-only)
const doubleAtom = atom((get) => get(countAtom) * 2)

// Atom leitura+escrita com lógica
const incrementAtom = atom(
  (get) => get(countAtom),
  (get, set, by: number = 1) => set(countAtom, get(countAtom) + by)
)

// atomFamily — atom por ID
const productAtom = atomFamily((id: string) =>
  atom(async () => {
    const res = await fetch(`/api/products/${id}`)
    return res.json()
  })
)

// Async atom com Suspense
const userAtom = atom(async () => {
  const res = await fetch('/api/user')
  return res.json()
})

function UserName() {
  const user = useAtomValue(userAtom) // Suspense automático
  return <span>{user.name}</span>
}

// Granularidade: cada item tem seu próprio atom
function TodoItem({ id }: { id: string }) {
  const [todo, setTodo] = useAtom(todoAtomFamily(id))
  // só re-renderiza quando ESTE todo muda
  return <input value={todo.text} onChange={e => setTodo({...todo, text: e.target.value})} />
}
Q.Jotai vs Zustand: quando escolher cada um?
A.Zustand: estado de domínio centralizado (cart, auth, produtos), quando você quer uma "fonte única de verdade" explícita. Jotai: estado granular de UI, atoms por ID (editando item específico), estado que é naturalmente derivado de outros. Muitos devs usam Zustand para domínio e Jotai para UI granular.
Q.Como funciona atom derivado no Jotai?
A.atom((get) => derivação): lê outros atoms via get(), Jotai rastreia dependências automaticamente. Quando qualquer atom lido mudar, o derivado recalcula. Equivalente a useMemo mas global — qualquer componente pode ler o derivado sem recalcular.
Q.Jotai funciona com SSR/Next.js?
A.Sim, com Provider e useHydrateAtoms para inicializar atoms com dados do servidor: `useHydrateAtoms([[userAtom, serverUser]])`. Sem Provider, atoms são globais (singleton) — problemático em SSR onde múltiplas requests compartilhariam estado. Com Provider por request, cada request tem seu próprio scope.
71/122← →