React geralmente renderiza novamente os componentes automaticamente, mas para para realmente entender como e quando forçar o React a renderizar novamente um componente, precisamos entender o funcionamento interno do React.
Desde o início da web, usamos HTML e CSS para definir a representação visual de um site. Isso não mudou, mas, com a introdução do JavaScript, novos conceitos que nos permitem ler e atualizar o HTML renderizado de uma página. Chamamos essa API de DOM .
Bibliotecas como jQuery se tornaram extremamente populares porque fornecem uma camada de abstração sobre a API DOM que fornece funcionalidade e compatibilidade aprimoradas , tornando mais fácil para os desenvolvedores construir aplicativos da Web.
Mas o jQuery tem suas limitações. Ele não resolve problemas cruciais que os desenvolvedores têm ao trabalhar com conteúdo carregado dinamicamente, como manter o estado do JavaScript (variáveis) e o DOM (HTML) em sincronia. Alterar uma variável em JavaScript não afeta o DOM diretamente.
Usar uma estrutura como o React pode resolver esse problema. O React depende do JavaScript para manter o estado de um aplicativo. Este objeto de estado mestre que contém uma referência JavaScript para cada objeto na página é denominado Virtual DOM . Quaisquer alterações no DOM virtual refletem automaticamente no DOM, e esse é o melhor truque mágico do React.
Mas como atualizamos o DOM virtual? Fazemos isso construindo componentes e trabalhando com estado e props.
A próxima pergunta que você pode ter é: o que acontece nos casos extremos quando um componente não está sendo atualizado conforme o esperado? É mesmo possível? Talvez, mas é complicado, então vamos discutir isso.
Por que os componentes React não são renderizados novamente?
Geralmente, forçar uma nova renderização do componente React não é a melhor prática, mesmo quando o React falha em atualizar os componentes automaticamente. Portanto, antes de considerar forçar uma nova renderização, devemos analisar nosso código, pois a mágica do React depende de sermos bons hosts.
Estado incorretamente atualizado no React
Vamos construir um componente simples para demonstrar um motivo comum pelo qual os componentes não são renderizados. Construiremos um aplicativo simples que mostrará um nome de usuário, Juan, e, após pressionar um botão, o nome mudará para Peter.
Aqui está uma demonstração do aplicativo com o código completo. Você provavelmente notou que depois de clicar no botão, nada acontece, embora tenhamos mudado nosso estado no botão:
function changeUserName () {user.name=”Peter”; setUser (usuário); }
O componente não mudou, então não houve gatilho de renderização novamente. Aqui está o motivo.
O React avalia as mudanças de estado verificando sua igualdade superficial (ou igualdade de referência), que verifica se a visualização e o novo valor para o estado fazem referência ao mesmo objeto. Em nosso exemplo, atualizamos uma das propriedades do objeto de usuário, mas tecnicamente tornamos setUser a mesma referência de objeto e, portanto, o React não percebeu nenhuma mudança em seu estado.
Estado, conforme descrito na documentação do React , devem ser tratados como imutáveis.
Então, como podemos consertar isso? Poderíamos criar um novo objeto com os valores corretos da seguinte maneira:
function changeUserName () {setUser ({… user, name:”Peter”}); }
Observe que estamos usando o operador spread em JavaScript para preservar as propriedades do objeto original enquanto atualiza sua propriedade de nome em um novo objeto. O resultado final pode ser observado aqui .
Adereços atualizados incorretamente sem mudança de estado
Embora possa parecer impossível, atualizar adereços incorretamente sem uma mudança de estado pode acontecer, e geralmente leva a bugs. Vejamos um exemplo.
Nesta demonstração , Eu construí um relógio que tem um grande problema: a hora não muda depois que eu carrego a tela pela primeira vez. Não é um relógio muito útil, certo?
Vamos dar uma olhada no código responsável por calcular a hora atual:
let myTime; função setMyTime () {myTime=new Date (); setTimeout (()=> {setMyTime ();}, 1000); } setMyTime ();
Este código parece feio e geralmente não é uma ótima maneira de codificar para um componente React, mas funciona. A cada segundo, o tempo de execução chamará a função setMyTime e atualizará a variável myTime, que é então passada para nosso componente Clock para renderização.
Esta demonstração não funciona como os adereços são um reflexo do estado, uma mudança independente nos adereços não acionará uma nova renderização. Para corrigi-lo, precisamos de um reescrever .
Observe que introduzimos o estado para gerenciar myTime e useEffect para iniciar e limpar os temporizadores para evitar bugs quando o componente re-renderiza. E funciona!
const [myTime, setMyTime]=useState (new Date ()); useEffect (()=> {var timerID=setInterval (()=> tick (), 1000); return ()=> clearInterval (timerID);}); função tick () {setMyTime (new Date ()); }
Forçando um componente React a renderizar novamente
Normalmente, é desaprovado forçar um componente a renderizar novamente, e a falha na re-renderização automática no React é muitas vezes devido a um bug subjacente no nossa base de código. Mas, se você tiver uma necessidade legítima de forçar um componente React a renderizar novamente, há algumas maneiras de fazer isso.
Forçando uma atualização em um componente de classe React
Se você está usando componentes de classe em seu código, você está com sorte. O React fornece uma API oficial para forçar uma nova renderização e é simples de implementar:
someMethod () {//Força uma renderização sem mudança de estado… this.forceUpdate (); }
Em qualquer usuário ou evento do sistema, você pode chamar o método this.forceUpdate (), que fará com que render () seja chamado no componente, ignorando shouldComponentUpdate () e, portanto, forçando o React a reavaliar o DOM virtual e estado do DOM.
Existem algumas ressalvas a este método:
React irá acionar os métodos de ciclo de vida normal para componentes filhos, incluindo shouldComponentUpdate (), então só podemos forçar o componente atual a ser reprocessado O VirtualDOM ainda validará seu estado com DOM, então o React só atualizará o DOM se a marcação mudar
Forçando uma atualização em um componente de função
Não há API oficial para renderizar novamente um componente de função, nem há um React Hook . Existem, no entanto, alguns truques inteligentes para indicar ao React que um componente deve ser atualizado.
Substitua os objetos de estado por uma nova instância deles
Digamos que queremos forçar uma atualização em nosso exemplo de alteração do usuário acima. Poderíamos fazer algo assim:
someMethod () {//Forçar uma renderização com uma mudança de estado simulada setUser ({… user}); }
Como o usuário é um objeto, podemos copiá-lo para um novo objeto e defini-lo como o novo estado. O mesmo pode se aplicar a qualquer outro objeto ou array.
2. Ter uma variável de estado vazia atualiza o gatilho
Este método é interessante, pois cria um novo objeto no estado. Nós apenas nos importamos com sua função de atualização da seguinte maneira:
const [, updateState]=React.useState (); const forceUpdate=React.useCallback (()=> updateState ({}), []);
Aqui, usamos useCallback para memorizar nossa função forceUpdate, mantendo-a constante durante todo o ciclo de vida do componente e tornando-a segura para ser passada para componentes filhos como suportes.
Aqui está um exemplo de como usar it:
import React from”react”; função padrão de exportação App () {const [, updateState]=React.useState (); const forceUpdate=React.useCallback (()=> updateState ({}), []); console.log (“renderizando…”); return (
); }
Agora, cada vez que clicarmos no botão Forçar reprocessamento , o componente será renderizado novamente. Você pode acessar a demonstração ao vivo aqui .
Conclusão
Em geral, devemos evitar forçar o React a renderizar novamente os componentes. Se o React não conseguir renderizar novamente os componentes automaticamente, é provável que um problema subjacente em seu projeto esteja impedindo que os componentes sejam atualizados corretamente.
No entanto, abordamos algumas maneiras comuns de forçar o React a renderizar novamente componentes, caso seja necessário. Boa codificação!