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

Elevando o estado

Um campo de entrada de texto fica ao lado de uma prévia que precisa mostrar o que foi digitado. 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 alterar o que o outro está guardando. A solução é mover esse estado para o componente pai mais próximo que ambos compartilham, e depois passar o valor para cada um como prop. Isso é chamado de elevação de 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 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 é renderizado novamente. Essa re-renderização envia o novo text de volta 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 local possível

Elevar o estado é um movimento que você faz apenas quando precisa. A regra orientadora é a colocalização de estado: mantenha cada pedaço de estado o mais baixo na árvore que ele conseguir ficar, perto do componente que realmente o usa, e eleve-o apenas quando outra coisa também precisar ler ou alterar. Um componente com estado que ninguém mais toca deve manter esse estado consigo mesmo.

Isso importa porque elevar tem um custo. A cada nível que um pedaço de estado sobe, o pai precisa passá-lo de volta como prop, e todo componente no meio precisa aceitar e repassar essa prop mesmo que nunca use o valor. Comece local. Eleve o estado apenas até o componente mais próximo que realmente precisa compartilhá-lo, não além.

Passando o setter para baixo

Repare que Form não passa apenas text para baixo. Ele também passa setText, como a prop onChange. Essa é a outra metade da elevação de estado: o componente que possui o estado disponibiliza uma forma de alterá-lo via props, e o filho chama essa função em vez de gerenciar o valor ele mesmo. TextInput nunca vê setText diretamente. Ele chama qualquer função que lhe foi dada, e o pai decide o que essa função realmente faz.

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

Escolha um componente para ser dono de um pedaço de estado e trate-o como a única fonte de verdade para esse valor. Não deixe um segundo componente manter uma cópia do mesmo dado em seu próprio estado e tentar manter os dois sincronizados manualmente. Duas cópias do mesmo valor divergem no momento em que um caminho de atualização é perdido, e perseguir esse bug é pior do que as props extras que teria custado elevar o estado desde o começo. Se um valor pode ser derivado do 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 através de 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 precisam do mesmo valor, é quando Context ou uma biblioteca de gerenciamento de estado compensa o esforço. Elevar estado e passar props para baixo ainda é a ferramenta certa para estado compartilhado por componentes que estão próximos; é a ferramenta errada quando 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 ao pai mais próximo que compartilham em vez de para um dos componentes. Esse pai mantém o estado, passa o valor para ambos, e passa uma função para que um filho possa solicitar mudanças. O filho nunca é dono do valor; ele usa o que lhe é dado 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 no estilo onChange. Mantenha o estado o mais local possível de outra forma; eleve apenas quando outra coisa também precisar. Para qualquer coisa compartilhada entre muitos componentes aninhados, Context é a ferramenta melhor, e o capítulo de Hooks cobre como usar.
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 de verdade por valor em vez de sincronizar cópias entre componentes. Observe prop drilling, uma prop que passa através de camadas que não a usam, como o sinal de que Context ou uma store é o ajuste melhor do que elevar mais.

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