Skip to content
This page has been auto-translated and may contain errors.View in English

Elevando o estado

Um campo de texto fica ao lado de uma prévia que precisa mostrar o que foi digitado nele. Ambos vivem na mesma árvore de componentes, mas o estado declarado dentro de um componente é invisível para seus vizinhos, então nem o input nem a prévia conseguem ler ou mudar o que o outro está guardando. A solução é mover esse estado para o componente pai mais próximo que ambos compartilham, depois passar o valor para baixo para cada um como uma prop. Isso é chamado de elevar o estado.

Aqui está esse par, compartilhando um valor:

jsx
import { useState } from 'react'

function Form() {
  const [text, setText] = useState('')

  return (
    <>
      <TextInput text={text} onChange={setText} />
      <TextDisplay text={text} />
    </>
  )
}

function TextInput({ text, onChange }) {
  return <input value={text} onChange={e => onChange(e.target.value)} />
}

function TextDisplay({ text }) {
  return <p>Você digitou: {text}</p>
}

Form é o pai comum mais próximo de TextInput e TextDisplay, então é lá que text vive. Ele passa text para baixo para ambos, e passa setText para TextInput com o nome onChange. Quando alguém digita, TextInput chama onChange com o novo valor, o estado de Form é atualizado, e Form re-renderiza. Essa re-renderização envia o novo text para baixo para ambos os filhos, então TextDisplay mostra exatamente o que está no input sem manter nenhum estado próprio.

Mantenha o estado o mais baixo possível

Elevar o estado é um movimento que você faz apenas quando precisa. A regra norteadora é colocação de estado: mantenha cada pedaço de estado o mais baixo na árvore possível, perto do componente que realmente o usa, e eleve-o apenas quando outro componente também precisar ler ou mudar. Um componente com estado que ninguém mais mexe deve manter esse estado só para si.

Isso importa porque elevar tem um custo. Cada nível que um pedaço de estado sobe, o pai tem que passá-lo para baixo novamente como uma prop, e cada componente no meio tem que aceitar e passar adiante essa prop mesmo que nunca use o valor. Comece local. Mova o estado apenas até o componente mais próximo que realmente precisa compartilhá-lo, nada além disso.

Passando o setter para baixo

Repare que Form não passa apenas text para baixo. Também passa setText, como a prop onChange. Esta é a outra metade de elevar o estado: o componente que possui o estado disponibiliza uma forma de mudá-lo através de props, e o filho chama essa função em vez de gerenciar o valor por si mesmo. TextInput nunca vê setText diretamente. Ele chama qualquer função que recebeu, e o pai decide o que essa função realmente faz.

Para estado compartilhado entre componentes aninhados muitos níveis de distância, passar props para baixo através de cada camada deixa de ser prático. React tem ferramentas para esse caso, Context entre elas, e Context cobre useContext, o hook que lê um valor sem passá-lo por cada componente no meio. Isso está além do que este capítulo cobre; o padrão acima é aquele para se usar primeiro.

Escolha um componente para possuir um dado pedaço de estado e trate-o como a única fonte da verdade para esse valor. Não deixe um segundo componente manter uma cópia do mesmo dado em seu próprio estado e tente manter os dois sincronizados manualmente. Duas cópias do mesmo valor se afastam no momento em que um caminho de atualização é perdido, e perseguir esse bug é pior do que os props extras que teria custado elevar o estado em primeiro lugar. Se um valor pode ser derivado de um estado que já existe em algum lugar, derive-o durante a renderização em vez de armazená-lo separadamente.

O sinal a observar é prop drilling: uma prop que passa por vários componentes puramente para alcançar um consumidor profundamente aninhado, com cada componente no meio passando-a adiante e nunca a usando. Uma ou duas camadas disso é normal e não vale a pena reestruturar. Quando se estende por muitas camadas, ou quando vários ramos não relacionados da árvore todos precisam do mesmo valor, é quando Context ou uma biblioteca de gerenciamento de estado justifica seu uso. Elevar o estado e passar props para baixo ainda é a ferramenta certa para estado compartilhado por componentes que estão perto um do outro; é a ferramenta errada uma vez que a árvore entre eles fica profunda.

JunoMova o estado compartilhado para o pai Quando dois componentes precisam do mesmo valor, o truque é dar o valor para seu pai compartilhado mais próximo em vez de qualquer um dos componentes. Esse pai mantém o estado, passa o valor para baixo para ambos, e passa para baixo uma função para que um filho possa pedir mudanças.

O filho nunca possui o valor; ele usa o que recebe e pede ao pai para atualizá-lo.

JunoMova o estado compartilhado para o pai Eleve o estado para o pai comum mais próximo quando dois componentes precisam compartilhá-lo, e passe o valor e seu setter para baixo como props, geralmente uma prop value e um callback estilo onChange. Mantenha o estado o mais local possível caso contrário; apenas eleve quando algo mais também precisar dele.

Para qualquer coisa compartilhada por muitos componentes aninhados, Context é a ferramenta melhor, e o capítulo de Context cobre como.

JunoMova o estado compartilhado para o pai Prefira estado colocalizado e eleve apenas até o consumidor compartilhado mais próximo, passando o valor e seu setter para baixo como props. Mantenha uma única fonte da verdade por valor em vez de sincronizar cópias entre componentes.

Observe prop drilling, uma prop que passa por camadas que não a usam, como o sinal de que Context ou um store é o ajuste melhor em vez de elevar mais.

Próximo: Effects, onde você usará useEffect para lidar com trabalho que acontece fora da renderização.