Pitfall

Recomendamos definir componentes como funções ao invés de classes. Veja como migrar.

Component é a classe base para os componentes React definidos como classes JavaScript. Componentes de classe ainda são suportados pelo React, mas não recomendamos usá-los em código novo.

class Greeting extends Component {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}

Referência

Component

Para definir um componente React como uma classe, estenda a classe Component integrada e defina um método render:

import { Component } from 'react';

class Greeting extends Component {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}

Somente o método render é obrigatório, outros métodos são opcionais.

Veja mais exemplos abaixo.


context

O contexto de um componente de classe está disponível como this.context. Ele só estará disponível se você especificar qual contexto deseja receber usando static contextType.

Um componente de classe só pode ler um contexto por vez.

class Button extends Component {
static contextType = ThemeContext;

render() {
const theme = this.context;
const className = 'button-' + theme;
return (
<button className={className}>
{this.props.children}
</button>
);
}
}

Note

Ler this.context em componentes de classe é equivalente a useContext em componentes de função.

Veja como migrar.


props

As props passadas para um componente de classe estão disponíveis como this.props.

class Greeting extends Component {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}

<Greeting name="Taylor" />

Note

Ler this.props em componentes de classe é equivalente a declarar props em componentes de função.

Veja como migrar.


state

O estado de um componente de classe está disponível como this.state. O campo state deve ser um objeto. Não mute o estado diretamente. Se você deseja alterar o estado, chame setState com o novo estado.

class Counter extends Component {
state = {
age: 42,
};

handleAgeChange = () => {
this.setState({
age: this.state.age + 1
});
};

render() {
return (
<>
<button onClick={this.handleAgeChange}>
Increment age
</button>
<p>You are {this.state.age}.</p>
</>
);
}
}

Note

Definir state em componentes de classe é equivalente a chamar useState em componentes de função.

Veja como migrar.


constructor(props)

O constructor é executado antes que seu componente de classe seja montado (adicionado à tela). Normalmente, um construtor é usado apenas para dois propósitos no React. Ele permite que você declare o state e faça o bind de seus métodos de classe para a instância da classe:

class Counter extends Component {
constructor(props) {
super(props);
this.state = { counter: 0 };
this.handleClick = this.handleClick.bind(this);
}

handleClick() {
// ...
}

Se você usar a sintaxe moderna do JavaScript, os construtores raramente são necessários. Em vez disso, você pode reescrever o código acima usando a sintaxe de campo de classe pública, que é suportada tanto por navegadores modernos quanto por ferramentas como Babel:

class Counter extends Component {
state = { counter: 0 };

handleClick = () => {
// ...
}

Um construtor não deve conter quaisquer efeitos colaterais ou assinaturas.

Parâmetros

  • props: as props iniciais do componente.

Retornos

O constructor não deve retornar nada.

Ressalvas

  • Não execute quaisquer efeitos colaterais ou assinaturas no construtor. Em vez disso, use componentDidMount para isso.

  • Dentro de um construtor, você precisa chamar super(props) antes de qualquer outra instrução. Se você não fizer isso, this.props será undefined enquanto o construtor é executado, o que pode ser confuso e causar erros.

  • Construtor é o único lugar onde você pode atribuir this.state diretamente. Em todos os outros métodos, você precisa usar this.setState() em vez disso. Não chame setState no construtor.

  • Quando você usa renderização do servidor, o construtor também será executado no servidor, seguido pelo método render. No entanto, os métodos de ciclo de vida como componentDidMount ou componentWillUnmount não serão executados no servidor.

  • Quando o Modo Restrito estiver ativado, o React chamará o constructor duas vezes no desenvolvimento e então descartará uma das instâncias. Isso ajuda você a perceber os efeitos colaterais acidentais que precisam ser movidos para fora do constructor.

Note

Não existe um equivalente exato para constructor em componentes de função. Para declarar o estado em um componente de função, chame useState. Para evitar o recálculo do estado inicial, passe uma função para useState.


componentDidCatch(error, info)

Se você definir componentDidCatch, o React o chamará quando algum componente filho (incluindo filhos distantes) lançar um erro durante a renderização. Isso permite que você registre esse erro em um serviço de relatório de erros em produção.

Normalmente, ele é usado em conjunto com static getDerivedStateFromError, que permite que você atualize o state em resposta a um erro e exiba uma mensagem de erro ao usuário. Um componente com esses métodos é chamado de limite de erro.

Veja um exemplo.

Parâmetros

  • error: O erro que foi lançado. Na prática, geralmente será uma instância de Error, mas isso não é garantido porque o JavaScript permite throw qualquer valor, incluindo strings ou até null.

  • info: Um objeto contendo informações adicionais sobre o erro. Seu campo componentStack contém um rastreamento de pilha com o componente que lançou, bem como os nomes e locais de origem de todos os seus componentes pai. Em produção, os nomes dos componentes serão minimizados. Se você configurar o relatório de erros de produção, poderá decodificar a pilha de componentes usando mapas de origem da mesma forma que faria para pilhas de erros JavaScript regulares.

Retornos

componentDidCatch não deve retornar nada.

Ressalvas

  • No passado, era comum chamar setState dentro de componentDidCatch para atualizar a UI e exibir a mensagem de erro de fallback. Isso está obsoleto em favor da definição de static getDerivedStateFromError.

  • As compilações de produção e desenvolvimento do React diferem ligeiramente na forma como componentDidCatch trata os erros. No desenvolvimento, os erros serão propagados para window, o que significa que qualquer window.onerror ou window.addEventListener('error', callback) interceptará os erros que foram capturados por componentDidCatch. Em produção, em vez disso, os erros não serão propagados, o que significa que qualquer manipulador de erros ancestral só receberá erros não explicitamente capturados por componentDidCatch.

Note

Ainda não existe um equivalente direto para componentDidCatch em componentes de função. Se você quiser evitar a criação de componentes de classe, escreva um único componente ErrorBoundary como acima e use-o em todo o seu aplicativo. Alternativamente, você pode usar o pacote react-error-boundary, que faz isso por você.


componentDidMount()

Se você definir o método componentDidMount, o React o chamará quando seu componente for adicionado (montado) na tela. Este é um lugar comum para iniciar a busca de dados, configurar assinaturas ou manipular os nós DOM.

Se você implementar componentDidMount, geralmente precisará implementar outros métodos de ciclo de vida para evitar erros. Por exemplo, se componentDidMount ler algum state ou props, você também deve implementar componentDidUpdate para lidar com suas alterações e componentWillUnmount para limpar o que componentDidMount estava fazendo.

class ChatRoom extends Component {
state = {
serverUrl: 'https://localhost:1234'
};

componentDidMount() {
this.setupConnection();
}

componentDidUpdate(prevProps, prevState) {
if (
this.props.roomId !== prevProps.roomId ||
this.state.serverUrl !== prevState.serverUrl
) {
this.destroyConnection();
this.setupConnection();
}
}

componentWillUnmount() {
this.destroyConnection();
}

// ...
}

Veja mais exemplos.

Parâmetros

componentDidMount não recebe nenhum parâmetro.

Retornos

componentDidMount não deve retornar nada.

Ressalvas

  • Quando o Modo Restrito estiver ativado, no desenvolvimento o React chamará componentDidMount, em seguida chamará imediatamente [componentWillUnmount ,] (#componentwillunmount) e depois chamará componentDidMount novamente. Isso ajuda você a notar se você se esqueceu de implementar componentWillUnmount ou se sua lógica não “espelha” totalmente o que componentDidMount faz.

  • Embora você possa chamar setState imediatamente em componentDidMount, é melhor evitar isso quando puder. Ele acionará uma renderização extra, mas isso acontecerá antes que o navegador atualize a tela. Isso garante que, mesmo que o render seja chamado duas vezes nesse caso, o usuário não verá o estado intermediário. Use este padrão com cautela porque ele geralmente causa problemas de desempenho. Na maioria dos casos, você deve ser capaz de atribuir o estado inicial no constructor em vez disso. No entanto, pode ser necessário para casos como modais e dicas de ferramentas quando você precisa medir um nó DOM antes de renderizar algo que dependa de seu tamanho ou posição.

Note

Para muitos casos de uso, definir componentDidMount, componentDidUpdate e componentWillUnmount juntos em componentes de classe é equivalente a chamar useEffect em componentes de função. Nos raros casos em que é importante que o código seja executado antes da pintura do navegador, useLayoutEffect é uma correspondência mais adequada.

Veja como migrar.


componentDidUpdate(prevProps, prevState, snapshot?)

Se você definir o método componentDidUpdate, o React o chamará imediatamente após seu componente ter sido renderizado novamente com props ou state atualizados. Este método não é chamado para a renderização inicial.

Você pode usá-lo para manipular o DOM após uma atualização. Este também é um lugar comum para fazer solicitações de rede, desde que você compare as props atuais com as props anteriores (por exemplo, uma solicitação de rede pode não ser necessária se as props não tiverem sido alteradas). Normalmente, você o usaria em conjunto com componentDidMount e componentWillUnmount:

class ChatRoom extends Component {
state = {
serverUrl: 'https://localhost:1234'
};

componentDidMount() {
this.setupConnection();
}

componentDidUpdate(prevProps, prevState) {
if (
this.props.roomId !== prevProps.roomId ||
this.state.serverUrl !== prevState.serverUrl
) {
this.destroyConnection();
this.setupConnection();
}
}

componentWillUnmount() {
this.destroyConnection();
}

// ...
}

Veja mais exemplos.

Parâmetros

  • prevProps: Props antes da atualização. Compare prevProps com this.props para determinar o que mudou.

  • prevState: State antes da atualização. Compare prevState com this.state para determinar o que mudou.

  • snapshot: Se você implementou getSnapshotBeforeUpdate, snapshot conterá o valor que você retornou desse método. Caso contrário, será undefined.

Retornos

componentDidUpdate não deve retornar nada.

Ressalvas

  • componentDidUpdate não será chamado se shouldComponentUpdate for definido e retornar false.

  • A lógica dentro de componentDidUpdate geralmente deve ser encapsulada em condições que comparam this.props com prevProps e this.state com prevState. Caso contrário, há o risco de criar loops infinitos.

  • Embora você possa chamar setState imediatamente em componentDidUpdate, é melhor evitar isso quando puder. Ele acionará uma renderização extra, mas isso acontecerá antes que o navegador atualize a tela. Isso garante que, mesmo que o render seja chamado duas vezes nesse caso, o usuário não verá o estado intermediário. Esse padrão geralmente causa problemas de desempenho, mas pode ser necessário para casos raros como modais e dicas de ferramentas quando você precisa medir um nó DOM antes de renderizar algo que dependa de seu tamanho ou posição.

Note

Para muitos casos de uso, definir componentDidMount, componentDidUpdate e componentWillUnmount juntos em componentes de classe é equivalente a chamar useEffect em componentes de função. Nos raros casos em que é importante que o código seja executado antes da pintura do navegador, useLayoutEffect é uma correspondência mais adequada.

Veja como migrar.


componentWillMount()

Deprecated

Esta API foi renomeada de componentWillMount para UNSAFE_componentWillMount. O nome antigo foi descontinuado. Em uma futura versão principal do React, somente o novo nome funcionará.

Execute o codemod rename-unsafe-lifecycles para atualizar automaticamente seus componentes.


componentWillReceiveProps(nextProps)

Deprecated

Esta API foi renomeada de componentWillReceiveProps para UNSAFE_componentWillReceiveProps. O nome antigo foi descontinuado. Em uma futura versão principal do React, somente o novo nome funcionará.

Execute o codemod rename-unsafe-lifecycles para atualizar automaticamente seus componentes.


componentWillUpdate(nextProps, nextState)

Deprecated

Esta API foi renomeada de componentWillUpdate para UNSAFE_componentWillUpdate. O nome antigo foi descontinuado. Em uma futura versão principal do React, somente o novo nome funcionará.

Execute o codemod rename-unsafe-lifecycles para atualizar automaticamente seus componentes.


componentWillUnmount()

Se você definir o método componentWillUnmount, o React o chamará antes que seu componente seja removido (desmontado) da tela. Este é um lugar comum para cancelar a busca de dados ou remover assinaturas.

A lógica dentro de componentWillUnmount deve “espelhar” a lógica dentro componentDidMount. Por exemplo, se componentDidMount configurar uma assinatura, componentWillUnmount deve limpar essa assinatura. Se a lógica de limpeza em seu componentWillUnmount lê algumas props ou state, você geralmente também precisará implementar componentDidUpdate para limpar os recursos (como assinaturas) correspondentes às props e state antigas.

class ChatRoom extends Component {
state = {
serverUrl: 'https://localhost:1234'
};

componentDidMount() {
this.setupConnection();
}

componentDidUpdate(prevProps, prevState) {
if (
this.props.roomId !== prevProps.roomId ||
this.state.serverUrl !== prevState.serverUrl
) {
this.destroyConnection();
this.setupConnection();
}
}

componentWillUnmount() {
this.destroyConnection();
}

// ...
}

Veja mais exemplos.

Parâmetros

componentWillUnmount não recebe nenhum parâmetro.

Retornos

componentWillUnmount não deve retornar nada.

Ressalvas

  • Quando o Strict Mode está ativado, no desenvolvimento, o React chamará componentDidMount, então chamará imediatamente componentWillUnmount e, em seguida, chamará componentDidMount novamente. Isso ajuda você a notar se esqueceu de implementar componentWillUnmount ou se sua lógica não “espelha” totalmente o que componentDidMount faz.

Note

Para muitos casos de uso, definir componentDidMount, componentDidUpdate e componentWillUnmount juntos em componentes de classe é equivalente a chamar useEffect em componentes de função. Nos raros casos em que é importante que o código seja executado antes da pintura do navegador, useLayoutEffect é uma correspondência mais próxima.

Veja como migrar.


forceUpdate(callback?)

Força um componente a renderizar novamente.

Normalmente, isso não é necessário. Se o método render do seu componente lê apenas de this.props, this.state ou this.context, ele renderizará novamente automaticamente quando você chamar setState dentro do seu componente ou de um de seus pais. No entanto, se o método render do seu componente lê diretamente de uma fonte de dados externa, você deve dizer ao React para atualizar a interface do usuário quando essa fonte de dados mudar. É isso que forceUpdate permite que você faça.

Tente evitar todos os usos de forceUpdate e leia apenas de this.props e this.state em render.

Parâmetros

  • opcional callback Se especificado, o React chamará o callback que você forneceu após a confirmação da atualização.

Retorna

forceUpdate não retorna nada.

Ressalvas

Note

Ler uma fonte de dados externa e forçar os componentes de classe a renderizar novamente em resposta às suas alterações com forceUpdate foi substituído por useSyncExternalStore em componentes de função.


getSnapshotBeforeUpdate(prevProps, prevState)

Se você implementar getSnapshotBeforeUpdate, o React irá chamá-lo imediatamente antes que o React atualize o DOM. Ele permite que seu componente capture algumas informações do DOM (por exemplo, a posição da rolagem) antes que ele seja potencialmente alterado. Qualquer valor retornado por este método do ciclo de vida será passado como um parâmetro para componentDidUpdate.

Por exemplo, você pode usá-lo em uma interface do usuário como um tópico de bate-papo que precisa preservar sua posição de rolagem durante as atualizações:

class ScrollingList extends React.Component {
constructor(props) {
super(props);
this.listRef = React.createRef();
}

getSnapshotBeforeUpdate(prevProps, prevState) {
// Estamos adicionando novos itens à lista?
// Capture a posição da rolagem para que possamos ajustar a rolagem mais tarde.
if (prevProps.list.length < this.props.list.length) {
const list = this.listRef.current;
return list.scrollHeight - list.scrollTop;
}
return null;
}

componentDidUpdate(prevProps, prevState, snapshot) {
// Se tivermos um valor de snapshot, acabamos de adicionar novos itens.
// Ajuste a rolagem para que esses novos itens não empurrem os antigos para fora da exibição.
// (snapshot aqui é o valor retornado de getSnapshotBeforeUpdate)
if (snapshot !== null) {
const list = this.listRef.current;
list.scrollTop = list.scrollHeight - snapshot;
}
}

render() {
return (
<div ref={this.listRef}>{/* ...conteúdo... */}</div>
);
}
}

No exemplo acima, é importante ler a propriedade scrollHeight diretamente em getSnapshotBeforeUpdate. Não é seguro lê-la em render, UNSAFE_componentWillReceiveProps ou UNSAFE_componentWillUpdate porque há uma possível lacuna de tempo entre a chamada desses métodos e a atualização do DOM pelo React.

Parâmetros

  • prevProps: Props antes da atualização. Compare prevProps com this.props para determinar o que mudou.

  • prevState: State antes da atualização. Compare prevState com this.state para determinar o que mudou.

Retorna

Você deve retornar um valor de snapshot de qualquer tipo que desejar ou null. O valor que você retornou será passado como o terceiro argumento para componentDidUpdate.

Ressalvas

Note

No momento, não há equivalente a getSnapshotBeforeUpdate para componentes de função. Este caso de uso é muito incomum, mas se você precisar dele, por enquanto você terá que escrever um componente de classe.


render()

O método render é o único método obrigatório em um componente de classe.

O método render deve especificar o que você deseja que apareça na tela, por exemplo:

import { Component } from 'react';

class Greeting extends Component {
render() {
return <h1>Olá, {this.props.name}!</h1>;
}
}

O React pode chamar render a qualquer momento, então você não deve presumir que ele seja executado em um momento específico. Normalmente, o método render deve retornar um pedaço de JSX, mas alguns outros tipos de retorno (como strings) são suportados. Para calcular o JSX retornado, o método render pode ler this.props, this.state e this.context.

Você deve escrever o método render como uma função pura, o que significa que ele deve retornar o mesmo resultado se as props, state e context forem os mesmos. Ele também não deve conter efeitos colaterais (como configurar assinaturas) ou interagir com as APIs do navegador. Efeitos colaterais devem acontecer em manipuladores de eventos ou métodos como componentDidMount.

Parâmetros

render não recebe nenhum parâmetro.

Retorna

render pode retornar qualquer nó React válido. Isso inclui elementos React, como <div />, strings, números, portais, nós vazios (null, undefined, true e false) e arrays de nós React.

Ressalvas

  • render deve ser escrito como uma função pura de props, state e context. Não deve ter efeitos colaterais.

  • render não será chamado se shouldComponentUpdate for definido e retornar false.

  • Quando o Strict Mode está ativado, o React chamará render duas vezes no desenvolvimento e depois descartará um dos resultados. Isso ajuda você a perceber os efeitos colaterais acidentais que precisam ser movidos de fora do método render.

  • Não há correspondência um-para-um entre a chamada render e a subsequente chamada componentDidMount ou componentDidUpdate. Alguns dos resultados da chamada render podem ser descartados pelo React quando for benéfico.


setState(nextState, callback?)

Chame setState para atualizar o state do seu componente React.

class Form extends Component {
state = {
name: 'Taylor',
};

handleNameChange = (e) => {
const newName = e.target.value;
this.setState({
name: newName
});
}

render() {
return (
<>
<input value={this.state.name} onChange={this.handleNameChange} />
<p>Olá, {this.state.name}.</p>
</>
);
}
}

setState enfileira alterações no state do componente. Ele diz ao React que este componente e seus filhos precisam renderizar novamente com o novo state. Esta é a principal maneira de atualizar a interface do usuário em resposta às interações.

Pitfall

Chamar setState não altera o estado atual no código já em execução:

function handleClick() {
console.log(this.state.name); // "Taylor"
this.setState({
name: 'Robin'
});
console.log(this.state.name); // Ainda "Taylor"!
}

Ele só afeta o que this.state retornará a partir da próxima renderização.

Você também pode passar uma função para setState. Ele permite que você atualize o state com base no state anterior:

handleIncreaseAge = () => {
this.setState(prevState => {
return {
age: prevState.age + 1
};
});
}

Você não precisa fazer isso, mas é útil se quiser atualizar o state várias vezes durante o mesmo evento.

Parâmetros

  • nextState: Um objeto ou uma função.

    • Se você passar um objeto como nextState, ele será superficialmente mesclado em this.state.
    • Se você passar uma função como nextState, ela será tratada como uma função atualizadora. Ela deve ser pura, deve receber o state e as props pendentes como argumentos e deve retornar o objeto a ser superficialmente mesclado em this.state. O React colocará sua função atualizadora em uma fila e renderizará novamente seu componente. Durante a próxima renderização, o React calculará o próximo state aplicando todos os atualizadores enfileirados ao state anterior.
  • opcional callback: Se especificado, o React chamará o callback que você forneceu após a confirmação da atualização.

Retorna

setState não retorna nada.

Ressalvas

  • Pense em setState como uma solicitação em vez de um comando imediato para atualizar o componente. Quando vários componentes atualizam seu state em resposta a um evento, o React irá agrupar suas atualizações e renderizá-las juntas em uma única passagem no final do evento. No raro caso em que você precisa forçar que uma atualização de state específica seja aplicada de forma síncrona, você pode envolvê-la em flushSync, mas isso pode prejudicar o desempenho.

  • setState não atualiza this.state imediatamente. Isso torna a leitura de this.state logo após a chamada setState um possível problema. Em vez disso, use componentDidUpdate ou o argumento callback de setState, cada um dos quais tem garantia de ser acionado após a aplicação da atualização. Se você precisar definir o state com base no state anterior, poderá passar uma função para nextState, conforme descrito acima.

Note

Chamar setState em componentes de classe é semelhante a chamar uma função set em componentes de função.

Veja como migrar.


shouldComponentUpdate(nextProps, nextState, nextContext)

Se você definir shouldComponentUpdate, o React irá chamá-lo para determinar se uma renderização novamente pode ser ignorada.

Se você está confiante de que deseja escrevê-lo manualmente, você pode comparar this.props com nextProps e this.state com nextState e retornar false para dizer ao React que a atualização pode ser ignorada.

class Rectangle extends Component {
state = {
isHovered: false
};

shouldComponentUpdate(nextProps, nextState) {
if (
nextProps.position.x === this.props.position.x &&
nextProps.position.y === this.props.position.y &&
nextProps.size.width === this.props.size.width &&
nextProps.size.height === this.props.size.height &&
nextState.isHovered === this.state.isHovered
) {
// Nada mudou, então uma renderização novamente é desnecessária
return false;
}
return true;
}

// ...
}

O React chama shouldComponentUpdate antes da renderização quando novas props ou state são recebidos. O padrão é true. Este método não é chamado para a renderização inicial ou quando forceUpdate é usado.

Parâmetros

  • nextProps: As próximas props que o componente está prestes a renderizar. Compare nextProps com this.props para determinar o que mudou.
  • nextState: O próximo state que o componente está prestes a renderizar. Compare nextState com this.state para determinar o que mudou.
  • nextContext: O próximo context que o componente está prestes a renderizar. Compare nextContext com this.context para determinar o que mudou. Disponível apenas se você especificar static contextType.

Retorna

Retorne true se você deseja que o componente renderize novamente. Esse é o comportamento padrão.

Retorne false para dizer ao React que renderizar novamente pode ser ignorado.

Ressalvas

  • Este método existe como uma otimização de desempenho. Se seu componente quebrar sem ele, corrija isso primeiro.

  • Considere usar PureComponent em vez de escrever shouldComponentUpdate manualmente. PureComponent compara superficialmente as props e o state e reduz a chance de que você ignore uma atualização necessária.

  • Não recomendamos fazer verificações de igualdade profunda ou usar JSON.stringify em shouldComponentUpdate. Isso torna o desempenho imprevisível e dependente da estrutura de dados de cada prop e state. No melhor dos casos, você corre o risco de introduzir paralisações de vários segundos em seu aplicativo e, no pior dos casos, corre o risco de travá-lo.

  • Retornar false não impede que os componentes filhos renderizem novamente quando o seu state mudar.

  • Retornar false não garante que o componente não irá renderizar novamente. O React usará o valor de retorno como uma dica, mas ainda poderá optar por renderizar novamente seu componente se fizer sentido fazê-lo por outros motivos.

Note

Otimizar componentes de classe com shouldComponentUpdate é semelhante a otimizar componentes de função com memo. Os componentes de função também oferecem otimização mais granular com useMemo.


UNSAFE_componentWillMount()

Se você definir UNSAFE_componentWillMount, o React o chamará imediatamente após o constructor. Ele existe apenas por razões históricas e não deve ser usado em nenhum código novo. Em vez disso, use uma das alternativas:

  • Para inicializar o state, declare state como um campo de classe ou defina this.state dentro do constructor.
  • Se você precisar executar um efeito colateral ou configurar uma assinatura, mova essa lógica para componentDidMount em vez disso.

Veja exemplos de como migrar de lifecycles inseguros.

Parâmetros

UNSAFE_componentWillMount não recebe nenhum parâmetro.

Retorna

UNSAFE_componentWillMount não deve retornar nada.

Ressalvas

  • UNSAFE_componentWillMount não será chamado se o componente implementar static getDerivedStateFromProps ou getSnapshotBeforeUpdate.

  • Apesar de sua nomenclatura, UNSAFE_componentWillMount não garante que o componente será montado se seu aplicativo usa recursos modernos do React, como Suspense. Se uma tentativa de renderização for suspensa (por exemplo, porque o código de algum componente filho ainda não foi carregado), o React jogará a árvore em andamento fora e tentará construir o componente do zero durante a próxima tentativa. É por isso que este método é “inseguro”. O código que depende da montagem (como adicionar uma assinatura) deve ir para componentDidMount.

  • UNSAFE_componentWillMount é o único método do ciclo de vida que é executado durante a renderização do servidor. Para todos os efeitos práticos, ele é idêntico ao constructor, então você deve usar o constructor para esse tipo de lógica.

Note

Chamar setState dentro de UNSAFE_componentWillMount em um componente de classe para inicializar o state é equivalente a passar esse state como o state inicial para useState em um componente de função.


UNSAFE_componentWillReceiveProps(nextProps, nextContext)

Se você definir UNSAFE_componentWillReceiveProps, o React irá chamá-lo quando o componente receber novas props. Ele existe apenas por razões históricas e não deve ser usado em nenhum código novo. Em vez disso, use uma das alternativas:

  • Se você precisar executar um efeito colateral (por exemplo, buscar dados, executar uma animação ou reinicializar uma assinatura) em resposta a alterações de prop, mova essa lógica para componentDidUpdate em vez disso.
  • Se você precisar evitar o recálculo de alguns dados somente quando uma prop mudar, use um auxiliar de memoização em vez disso.
  • Se você precisar “resetar” algum state quando uma prop mudar, considere tornar um componente totalmente controlado ou totalmente não controlado com uma chave em vez disso.
  • Se você precisar “ajustar” algum state quando uma prop mudar, verifique se você pode calcular todas as informações necessárias apenas a partir das props durante a renderização. Se não for possível, use static getDerivedStateFromProps em vez disso.

Veja exemplos de como migrar de lifecycles inseguros.

Parâmetros ```text

  • nextProps: As próximas props que o componente está prestes a receber de seu componente pai. Compare nextProps com this.props para determinar o que mudou.
  • nextContext: O próximo contexto que o componente está prestes a receber do provedor mais próximo. Compare nextContext com this.context para determinar o que mudou. Disponível somente se você especificar static contextType.

Retorna

UNSAFE_componentWillReceiveProps não deve retornar nada.

Ressalvas

  • UNSAFE_componentWillReceiveProps não será chamado se o componente implementar static getDerivedStateFromProps ou getSnapshotBeforeUpdate.

  • Apesar de seu nome, UNSAFE_componentWillReceiveProps não garante que o componente receberá essas props se seu aplicativo usar recursos modernos do React como Suspense. Se uma tentativa de renderização for suspensa (por exemplo, porque o código de algum componente filho ainda não foi carregado), o React descartará a árvore em andamento e tentará construir o componente do zero durante a próxima tentativa. No momento da próxima tentativa de renderização, as props podem ser diferentes. É por isso que este método é “unsafe”. O código que deve ser executado apenas para atualizações confirmadas (como redefinir uma assinatura) deve ir para componentDidUpdate.

  • UNSAFE_componentWillReceiveProps não significa que o componente recebeu props diferentes da última vez. Você precisa comparar nextProps e this.props por conta própria para verificar se algo mudou.

  • O React não chama UNSAFE_componentWillReceiveProps com as props iniciais durante a montagem. Ele só chama este método se algumas das props do componente forem atualizadas. Por exemplo, chamar setState não aciona geralmente UNSAFE_componentWillReceiveProps dentro do mesmo componente.

Note

Chamar setState dentro de UNSAFE_componentWillReceiveProps em um componente de classe para “ajustar” o estado é equivalente a chamar a função set de useState durante a renderização em um componente de função.


UNSAFE_componentWillUpdate(nextProps, nextState)

Se você definir UNSAFE_componentWillUpdate, o React o chamará antes de renderizar com as novas props ou estado. Ele só existe por razões históricas e não deve ser usado em nenhum código novo. Em vez disso, use uma das alternativas:

  • Se você precisar executar um efeito colateral (por exemplo, buscar dados, executar uma animação ou reinicializar uma assinatura) em resposta a alterações de prop ou estado, mova essa lógica para componentDidUpdate em vez disso.
  • Se você precisar ler algumas informações do DOM (por exemplo, para salvar a posição atual da rolagem) para que possa usá-la em componentDidUpdate posteriormente, leia-a dentro de getSnapshotBeforeUpdate em vez disso.

Veja exemplos de como migrar de ciclos de vida inseguros.

Parâmetros

  • nextProps: As próximas props que o componente está prestes a renderizar. Compare nextProps com this.props para determinar o que mudou.
  • nextState: O próximo estado com o qual o componente está prestes a renderizar. Compare nextState com this.state para determinar o que mudou.

Retorna

UNSAFE_componentWillUpdate não deve retornar nada.

Ressalvas

  • UNSAFE_componentWillUpdate não será chamado se shouldComponentUpdate for definido e retornar false.

  • UNSAFE_componentWillUpdate não será chamado se o componente implementar static getDerivedStateFromProps ou getSnapshotBeforeUpdate.

  • Não é suportado chamar setState (ou qualquer método que leve a setState ser chamado, como despachar uma ação do Redux) durante componentWillUpdate.

  • Apesar de seu nome, UNSAFE_componentWillUpdate não garante que o componente será atualizado se seu aplicativo usar recursos modernos do React como Suspense. Se uma tentativa de renderização for suspensa (por exemplo, porque o código de algum componente filho ainda não foi carregado), o React descartará a árvore em andamento e tentará construir o componente do zero durante a próxima tentativa. No momento da próxima tentativa de renderização, as props e o estado podem ser diferentes. É por isso que este método é “unsafe”. O código que deve ser executado apenas para atualizações confirmadas (como redefinir uma assinatura) deve ir para componentDidUpdate.

  • UNSAFE_componentWillUpdate não significa que o componente recebeu props ou estado diferentes da última vez. Você precisa comparar nextProps com this.props e nextState com this.state por conta própria para verificar se algo mudou.

  • O React não chama UNSAFE_componentWillUpdate com as props e o estado iniciais durante a montagem.

Note

Não existe equivalente direto para UNSAFE_componentWillUpdate em componentes de função.


static contextType

Se você quiser ler this.context do seu componente de classe, você deve especificar qual contexto ele precisa ler. O contexto que você especifica como static contextType deve ser um valor criado anteriormente por createContext.

class Button extends Component {
static contextType = ThemeContext;

render() {
const theme = this.context;
const className = 'button-' + theme;
return (
<button className={className}>
{this.props.children}
</button>
);
}
}

Note

Ler this.context em componentes de classe é equivalente a useContext em componentes de função.

Veja como migrar.


static defaultProps

Você pode definir static defaultProps para definir as props padrão para a classe. Elas serão usadas para props undefined e ausentes, mas não para props null.

Por exemplo, aqui está como você define que a prop color deve ser definida por padrão como 'blue':

class Button extends Component {
static defaultProps = {
color: 'blue'
};

render() {
return <button className={this.props.color}>click me</button>;
}
}

Se a prop color não for fornecida ou for undefined, ela será definida por padrão como 'blue':

<>
{/* this.props.color é "blue" */}
<Button />

{/* this.props.color é "blue" */}
<Button color={undefined} />

{/* this.props.color é null */}
<Button color={null} />

{/* this.props.color é "red" */}
<Button color="red" />
</>

Note

Definir defaultProps em componentes de classe é semelhante a usar valores padrão em componentes de função.


static getDerivedStateFromError(error)

Se você definir static getDerivedStateFromError, o React o chamará quando um componente filho (incluindo filhos distantes) lançar um erro durante a renderização. Isso permite que você exiba uma mensagem de erro em vez de limpar a UI.

Normalmente, ele é usado em conjunto com componentDidCatch, que permite enviar o relatório de erro para algum serviço de análise. Um componente com esses métodos é chamado de borda de erro.

Veja um exemplo.

Parâmetros

  • error: O erro que foi lançado. Na prática, geralmente será uma instância de Error, mas isso não é garantido porque o JavaScript permite throw qualquer valor, incluindo strings ou até mesmo null.

Retorna

static getDerivedStateFromError deve retornar o estado que diz ao componente para exibir a mensagem de erro.

Ressalvas

  • static getDerivedStateFromError deve ser uma função pura. Se você deseja executar um efeito colateral (por exemplo, chamar um serviço de análise), também precisa implementar componentDidCatch.

Note

Ainda não existe um equivalente direto para static getDerivedStateFromError em componentes de função. Se você quiser evitar a criação de componentes de classe, escreva um único componente ErrorBoundary como acima e use-o em todo o seu aplicativo. Como alternativa, use o pacote react-error-boundary, que faz isso.


static getDerivedStateFromProps(props, state)

Se você definir static getDerivedStateFromProps, o React o chamará logo antes de chamar o render, tanto na montagem inicial quanto nas atualizações subsequentes. Ele deve retornar um objeto para atualizar o estado ou null para não atualizar nada.

Este método existe para casos de uso raros, onde o estado depende de alterações nas props ao longo do tempo. Por exemplo, este componente Form redefine o estado email quando a prop userID muda:

class Form extends Component {
state = {
email: this.props.defaultEmail,
prevUserID: this.props.userID
};

static getDerivedStateFromProps(props, state) {
// Sempre que o usuário atual mudar,
// Redefinir quaisquer partes do estado que estejam vinculadas a esse usuário.
// Neste exemplo simples, é apenas o e-mail.
if (props.userID !== state.prevUserID) {
return {
prevUserID: props.userID,
email: props.defaultEmail
};
}
return null;
}

// ...
}

Observe que este padrão requer que você mantenha um valor anterior da prop (como userID) no estado (como prevUserID).

Pitfall

Derivar o estado leva a um código prolixo e dificulta a reflexão sobre seus componentes. Certifique-se de estar familiarizado com alternativas mais simples:

Parâmetros

  • props: As próximas props que o componente está prestes a renderizar.
  • state: O próximo estado com o qual o componente está prestes a renderizar.

Retorna

static getDerivedStateFromProps retorna um objeto para atualizar o estado ou null para não atualizar nada.

Ressalvas

  • Este método é disparado em cada renderização, independentemente da causa. Isso é diferente de UNSAFE_componentWillReceiveProps, que só é disparado quando os pais causam uma nova renderização e não como resultado de um setState local.

  • Este método não tem acesso à instância do componente. Se você quiser, poderá reutilizar algum código entre static getDerivedStateFromProps e os outros métodos de classe, extraindo funções puras das props e do estado do componente fora da definição da classe.

Note

Implementar static getDerivedStateFromProps em um componente de classe é equivalente a chamar a função set de useState durante a renderização em um componente de função.


Uso

Definindo um componente de classe

Para definir um componente React como uma classe, estenda a classe Component integrada e defina um método render:

import { Component } from 'react';

class Greeting extends Component {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}

O React chamará seu método render sempre que precisar descobrir o que exibir na tela. Normalmente, você retornará algum JSX dele. Seu método render deve ser uma função pura:, ele só deve calcular o JSX.

Semelhante aos componentes de função, um componente de classe pode receber informações por props de seu componente pai. No entanto, a sintaxe para ler props é diferente. Por exemplo, se o componente pai renderizar <Greeting name="Taylor" />, então você pode ler a prop name de this.props, como this.props.name:

import { Component } from 'react';

class Greeting extends Component {
  render() {
    return <h1>Hello, {this.props.name}!</h1>;
  }
}

export default function App() {
  return (
    <>
      <Greeting name="Sara" />
      <Greeting name="Cahal" />
      <Greeting name="Edite" />
    </>
  );
}

Observe que Hooks (funções começando com use, como useState) não são compatíveis com componentes de classe.

Pitfall

Recomendamos definir componentes como funções em vez de classes. Veja como migrar.


Adicionando estado a um componente de classe

Para adicionar estado a uma classe, atribua um objeto a uma propriedade chamada state. Para atualizar o estado, chame this.setState.

import { Component } from 'react';

export default class Counter extends Component {
  state = {
    name: 'Taylor',
    age: 42,
  };

  handleNameChange = (e) => {
    this.setState({
      name: e.target.value
    });
  }

  handleAgeChange = () => {
    this.setState({
      age: this.state.age + 1 
    });
  };

  render() {
    return (
      <>
        <input
          value={this.state.name}
          onChange={this.handleNameChange}
        />
        <button onClick={this.handleAgeChange}>
          Increment age
        </button>
        <p>Hello, {this.state.name}. You are {this.state.age}.</p>
      </>
    );
  }
}

Pitfall

Recomendamos definir componentes como funções em vez de classes. Veja como migrar.


Adicionando métodos do ciclo de vida a um componente de classe

Existem alguns métodos especiais que você pode definir em sua classe.

Se você definir o método componentDidMount, o React o chamará quando seu componente for adicionado (montado) à tela. O React chamará componentDidUpdate após o seu componente renderizar novamente, devido a props ou estado alterados. O React chamará componentWillUnmount depois que seu componente for removido (desmontado) da tela.

Se você implementar componentDidMount, geralmente precisará implementar todos os três ciclos de vida para evitar erros. Por exemplo, se componentDidMount lê algum estado ou props, você também precisa implementar componentDidUpdate para lidar com suas alterações e componentWillUnmount para limpar o que componentDidMount estava fazendo.

Por exemplo, este componente ChatRoom mantém uma conexão de chat sincronizada com props e estado:

import { Component } from 'react';
import { createConnection } from './chat.js';

export default class ChatRoom extends Component {
  state = {
    serverUrl: 'https://localhost:1234'
  };

  componentDidMount() {
    this.setupConnection();
  }

  componentDidUpdate(prevProps, prevState) {
    if (
      this.props.roomId !== prevProps.roomId ||
      this.state.serverUrl !== prevState.serverUrl
    ) {
      this.destroyConnection();
      this.setupConnection();
    }
  }```js
import { Component } from 'react';

export default class ChatRoom extends Component {
  state = {
    serverUrl: 'https://localhost:1234'
  };

  componentDidMount() {
    this.setupConnection();
  }

  componentDidUpdate(prevProps, prevState) {
    if (
      this.props.roomId !== prevProps.roomId ||
      this.state.serverUrl !== prevState.serverUrl
    ) {
      this.destroyConnection();
      this.setupConnection();
    }
  }

  componentWillUnmount() {
    this.destroyConnection();
  }

  setupConnection() {
    this.connection = createConnection(
      this.state.serverUrl,
      this.props.roomId
    );
    this.connection.connect();    
  }

  destroyConnection() {
    this.connection.disconnect();
    this.connection = null;
  }

  render() {
    return (
      <>
        <label>
          Server URL:{' '}
          <input
            value={this.state.serverUrl}
            onChange={e => {
              this.setState({
                serverUrl: e.target.value
              });
            }}
          />
        </label>
        <h1>Bem vindo(a) à sala {this.props.roomId}!</h1>
      </>
    );
  }
}

Observe que, em desenvolvimento, quando o Modo Strict está ativado, o React chamará componentDidMount, chamará imediatamente componentWillUnmount e, em seguida, chamará componentDidMount novamente. Isso ajuda você a notar se você esqueceu de implementar componentWillUnmount ou se sua lógica não “espelha” totalmente o que componentDidMount faz.

Pitfall

Recomendamos definir componentes como funções em vez de classes. Veja como migrar.


Capturando erros de renderização com um limite de erro

Por padrão, se seu aplicativo lançar um erro durante a renderização, o React removerá sua UI da tela. Para evitar isso, você pode encapsular uma parte da sua UI em um limite de erro. Um limite de erro é um componente especial que permite que você mostre alguma UI de fallback em vez da parte que travou — por exemplo, uma mensagem de erro.

Para implementar um componente de limite de erro, você precisa fornecer static getDerivedStateFromError que permite que você atualize o estado em resposta a um erro e exiba uma mensagem de erro ao usuário. Você também pode implementar opcionalmente componentDidCatch para adicionar alguma lógica extra, por exemplo, para registrar o erro em um serviço de análise.

With captureOwnerStack you can include the Owner Stack during development.

import * as React from 'react';

class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}

static getDerivedStateFromError(error) {
// Atualize o estado para que a próxima renderização mostre a UI de fallback.
return { hasError: true };
}

componentDidCatch(error, info) {
logErrorToMyService(
error,
// Example "componentStack":
// in ComponentThatThrows (created by App)
// in ErrorBoundary (created by App)
// in div (created by App)
// in App
info.componentStack,
// Warning: `captureOwnerStack` is not available in production.
React.captureOwnerStack(),
);
}

render() {
if (this.state.hasError) {
// Você pode renderizar qualquer UI de fallback personalizada
return this.props.fallback;
}

return this.props.children;
}
}

Então você pode encapsular uma parte da sua árvore de componentes com ele:

<ErrorBoundary fallback={<p>Algo deu errado</p>}>
<Profile />
</ErrorBoundary>

Se Profile ou seu componente filho lançarem um erro, ErrorBoundary “capturará” esse erro, exibirá uma UI de fallback com a mensagem de erro que você forneceu e enviará um relatório de erro de produção para seu serviço de relatório de erro.

Você não precisa encapsular cada componente em um limite de erro separado. Quando você pensa sobre a granularidade dos limites de erro, considere onde faz sentido exibir uma mensagem de erro. Por exemplo, em um aplicativo de mensagens, faz sentido colocar um limite de erro ao redor da lista de conversas. Também faz sentido colocar um ao redor de cada mensagem individual. No entanto, não faria sentido colocar um limite em cada avatar.

Note

Atualmente, não há como escrever um limite de erro como um componente de função. No entanto, você não precisa escrever a classe de limite de erro sozinho. Por exemplo, você pode usar react-error-boundary em vez disso.


Alternativas

Migrando um componente simples de uma classe para uma função

Normalmente, você irá definir componentes como funções em vez disso.

Por exemplo, suponha que você esteja convertendo este componente de classe Greeting em uma função:

import { Component } from 'react';

class Greeting extends Component {
  render() {
    return <h1>Hello, {this.props.name}!</h1>;
  }
}

export default function App() {
  return (
    <>
      <Greeting name="Sara" />
      <Greeting name="Cahal" />
      <Greeting name="Edite" />
    </>
  );
}

Defina uma função chamada Greeting. É aqui que você moverá o corpo da sua função render.

function Greeting() {
// ... mova o código do método render aqui ...
}

Em vez de this.props.name, defina a name prop usando a sintaxe de desestruturação e leia-a diretamente:

function Greeting({ name }) {
return <h1>Hello, {name}!</h1>;
}

Aqui está um exemplo completo:

function Greeting({ name }) {
  return <h1>Hello, {name}!</h1>;
}

export default function App() {
  return (
    <>
      <Greeting name="Sara" />
      <Greeting name="Cahal" />
      <Greeting name="Edite" />
    </>
  );
}


Migrando um componente com estado de uma classe para uma função

Suponha que você esteja convertendo este componente de classe Counter em uma função:

import { Component } from 'react';

export default class Counter extends Component {
  state = {
    name: 'Taylor',
    age: 42,
  };

  handleNameChange = (e) => {
    this.setState({
      name: e.target.value
    });
  }

  handleAgeChange = (e) => {
    this.setState({
      age: this.state.age + 1 
    });
  };

  render() {
    return (
      <>
        <input
          value={this.state.name}
          onChange={this.handleNameChange}
        />
        <button onClick={this.handleAgeChange}>
          Increment age
        </button>
        <p>Hello, {this.state.name}. You are {this.state.age}.</p>
      </>
    );
  }
}

Comece declarando uma função com as variáveis de estado necessárias:

import { useState } from 'react';

function Counter() {
const [name, setName] = useState('Taylor');
const [age, setAge] = useState(42);
// ...

Em seguida, converta os manipuladores de eventos:

function Counter() {
const [name, setName] = useState('Taylor');
const [age, setAge] = useState(42);

function handleNameChange(e) {
setName(e.target.value);
}

function handleAgeChange() {
setAge(age + 1);
}
// ...

Finalmente, substitua todas as referências começando com this pelas variáveis e funções que você definiu em seu componente. Por exemplo, substitua this.state.age por age e substitua this.handleNameChange por handleNameChange.

Aqui está um componente totalmente convertido:

import { useState } from 'react';

export default function Counter() {
  const [name, setName] = useState('Taylor');
  const [age, setAge] = useState(42);

  function handleNameChange(e) {
    setName(e.target.value);
  }

  function handleAgeChange() {
    setAge(age + 1);
  }

  return (
    <>
      <input
        value={name}
        onChange={handleNameChange}
      />
      <button onClick={handleAgeChange}>
        Increment age
      </button>
      <p>Hello, {name}. You are {age}.</p>
    </>
  )
}


Migrando um componente com métodos de ciclo de vida de uma classe para uma função

Suponha que você esteja convertendo este componente de classe ChatRoom com métodos de ciclo de vida em uma função:

import { Component } from 'react';
import { createConnection } from './chat.js';

export default class ChatRoom extends Component {
  state = {
    serverUrl: 'https://localhost:1234'
  };

  componentDidMount() {
    this.setupConnection();
  }

  componentDidUpdate(prevProps, prevState) {
    if (
      this.props.roomId !== prevProps.roomId ||
      this.state.serverUrl !== prevState.serverUrl
    ) {
      this.destroyConnection();
      this.setupConnection();
    }
  }

  componentWillUnmount() {
    this.destroyConnection();
  }

  setupConnection() {
    this.connection = createConnection(
      this.state.serverUrl,
      this.props.roomId
    );
    this.connection.connect();    
  }

  destroyConnection() {
    this.connection.disconnect();
    this.connection = null;
  }

  render() {
    return (
      <>
        <label>
          Server URL:{' '}
          <input
            value={this.state.serverUrl}
            onChange={e => {
              this.setState({
                serverUrl: e.target.value
              });
            }}
          />
        </label>
        <h1>Welcome to the {this.props.roomId} room!</h1>
      </>
    );
  }
}

Primeiro, verifique se seu componentWillUnmount faz o oposto de componentDidMount. No exemplo acima, isso é verdade: ele desconecta a conexão que componentDidMount configura. Se essa lógica estiver faltando, adicione-a primeiro.

Em seguida, verifique se seu método componentDidUpdate lida com as alterações em quaisquer props e estado que você está usando em componentDidMount. No exemplo acima, componentDidMount chama setupConnection, que lê this.state.serverUrl e this.props.roomId. É por isso que componentDidUpdate verifica se this.state.serverUrl e this.props.roomId foram alterados e redefinem a conexão, caso tenham sido. Se a lógica do seu componentDidUpdate estiver faltando ou não manipular as alterações em todas as props e estado relevantes, corrija-a primeiro.

No exemplo acima, a lógica dentro dos métodos de ciclo de vida conecta o componente a um sistema fora do React (um servidor de bate-papo). Para conectar um componente a um sistema externo, descreva essa lógica como um único Efeito:

import { useState, useEffect } from 'react';

function ChatRoom({ roomId }) {
const [serverUrl, setServerUrl] = useState('https://localhost:1234');

useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.connect();
return () => {
connection.disconnect();
};
}, [serverUrl, roomId]);

// ...
}

Esta chamada useEffect é equivalente à lógica nos métodos de ciclo de vida acima. Se seus métodos de ciclo de vida fizerem várias coisas não relacionadas, divida-os em vários Efeitos independentes. Aqui está um exemplo completo com o qual você pode brincar:

import { useState, useEffect } from 'react';
import { createConnection } from './chat.js';

export default function ChatRoom({ roomId }) {
  const [serverUrl, setServerUrl] = useState('https://localhost:1234');

  useEffect(() => {
    const connection = createConnection(serverUrl, roomId);
    connection.connect();
    return () => {
      connection.disconnect();
    };
  }, [roomId, serverUrl]);

  return (
    <>
      <label>
        Server URL:{' '}
        <input
          value={serverUrl}
          onChange={e => setServerUrl(e.target.value)}
        />
      </label>
      <h1>Bem vindo(a) à sala {roomId}!</h1>
    </>
  );
}

Note

Se seu componente não sincroniza com nenhum sistema externo, você pode não precisar de um Efeito.


Migrando um componente com contexto de uma classe para uma função

Neste exemplo, os componentes de classe Panel e Button leem o contexto de this.context:

import { createContext, Component } from 'react';

const ThemeContext = createContext(null);

class Panel extends Component {
  static contextType = ThemeContext;

  render() {
    const theme = this.context;
    const className = 'panel-' + theme;
    return (
      <section className={className}>
        <h1>{this.props.title}</h1>
        {this.props.children}
      </section>
    );    
  }
}

class Button extends Component {
  static contextType = ThemeContext;

  render() {
    const theme = this.context;
    const className = 'button-' + theme;
    return (
      <button className={className}>
        {this.props.children}
      </button>
    );
  }
}

function Form() {
  return (
    <Panel title="Welcome">
      <Button>Sign up</Button>
      <Button>Log in</Button>
    </Panel>
  );
}

export default function MyApp() {
  return (
    <ThemeContext.Provider value="dark">
      <Form />
    </ThemeContext.Provider>
  )
}

Quando você os converte em componentes de função, substitua this.context pelas chamadas [useContext]:

import { createContext, useContext } from 'react';

const ThemeContext = createContext(null);

function Panel({ title, children }) {
  const theme = useContext(ThemeContext);
  const className = 'panel-' + theme;
  return (
    <section className={className}>
      <h1>{title}</h1>
      {children}
    </section>
  )
}

function Button({ children }) {
  const theme = useContext(ThemeContext);
  const className = 'button-' + theme;
  return (
    <button className={className}>
      {children}
    </button>
  );
}

function Form() {
  return (
    <Panel title="Welcome">
      <Button>Sign up</Button>
      <Button>Log in</Button>
    </Panel>
  );
}

export default function MyApp() {
  return (
    <ThemeContext.Provider value="dark">
      <Form />
    </ThemeContext.Provider>
  )
}