Apresentamos a você uma tradução do artigo de Chidume Nnamdi, publicado no blog.bitsrc.io. Se você quiser aprender como evitar renderizações desnecessárias e como novas ferramentas são úteis no React, seja bem-vindo ao gato.

A equipe React.js está trabalhando duro para fazer com que o React seja executado o mais rápido possível. Para permitir que os desenvolvedores acelerem seus aplicativos React, as seguintes ferramentas foram adicionadas a ele:
- React.lazy e Suspense para carregamento atrasado do componente;
- Componente puro
- os ganchos do ciclo de vida shouldComponentUpdate (...) {...}.
Neste artigo, consideraremos, entre outras, outra ferramenta de otimização adicionada no React v16.6 para acelerar as funções dos componentes -
React.memo .
Dica: Use
Bit para instalar e compartilhar os componentes do React. Use seus componentes para criar novos aplicativos e compartilhá-los com a equipe para acelerar as coisas. Experimente!

Renderização extra
No React, cada componente corresponde a uma unidade de visualização. Componentes também têm estados. Quando o valor do estado muda devido a ações do usuário, o componente percebe que é necessário redesenhar. O componente React pode ser redesenhado várias vezes. Em alguns casos, isso é necessário, mas na maioria das vezes você pode ficar sem um renderizador, especialmente porque ele diminui bastante a velocidade do aplicativo.
Considere o seguinte componente:
import React from 'react'; class TestC extends React.Component { constructor(props) { super(props); this.state = { count: 0 } } componentWillUpdate(nextProps, nextState) { console.log('componentWillUpdate') } componentDidUpdate(prevProps, prevState) { console.log('componentDidUpdate') } render() { return ( <div > {this.state.count} <button onClick={()=>this.setState({count: 1})}>Click Me</button> </div> ); } } export default TestC;
O valor inicial do estado {count: 0} é 0. Se você clicar no botão Clique em mim, o estado da contagem se tornará 1. Na tela, 0 também será alterado para 1. Mas se clicarmos novamente no botão, os problemas começam: o componente não deve ser redesenhado, porque a condição não mudou. O valor do contador "para" é 1, o novo valor também é um, o que significa que não há necessidade de atualizar o DOM.
Para ver a atualização do nosso TestC, no qual o mesmo estado é definido duas vezes, adicionei dois métodos de ciclo de vida. React inicia o ciclo componentWillUpdate quando o componente é atualizado / redesenhado devido a uma alteração de estado. O ciclo componentdidUpdate React inicia quando um componente é renderizado com êxito.
Se iniciarmos o componente no navegador e tentarmos clicar no botão Clique em mim várias vezes, obteremos o seguinte resultado:

Repetir a entrada componentWillUpdate em nosso console indica que o componente é redesenhado mesmo quando o estado não muda. Esta é uma renderização extra.
Componente puro / shouldComponentUpdate
O gancho do ciclo de vida do shouldComponentUpdate ajudará a evitar renderizações desnecessárias nos componentes do React.
O React inicia o método
shouldComponentUpdate no início da renderização do componente e recebe uma luz verde desse método para continuar o processo ou um sinal de que o processo está
inibido .
Deixe o shouldComponentUpdate parecer assim:
shouldComponentUpdate(nextProps, nextState) { return true }
nextProps
: o próximo valor de props
que o componente receberá;nextState
: o próximo valor do state
que o componente receberá.
Portanto, permitimos que o React processe o componente porque o valor de retorno é
true
.
Suponha que escrevamos o seguinte:
shouldComponentUpdate(nextProps, nextState) { return false }
Nesse caso, proibimos o React de renderizar o componente, porque
false
retornado.
Do exposto, segue-se que, para renderizar o componente, precisamos retornar
true
. Agora podemos reescrever o componente TestC da seguinte maneira:
import React from 'react'; class TestC extends React.Component { constructor(props) { super(props); this.state = { count: 0 } } componentWillUpdate(nextProps, nextState) { console.log('componentWillUpdate') } componentDidUpdate(prevProps, prevState) { console.log('componentDidUpdate') } shouldComponentUpdate(nextProps, nextState) { if (this.state.count === nextState.count) { return false } return true } render() { return ( <div> { this.state.count } <button onClick = { () => this.setState({ count: 1 }) }> Click Me </button> </div> ); } } export default TestC;
Adicionamos um gancho shouldComponentUpdate ao componente TestC. Agora, o valor da
count
no objeto de estado atual
this.state.count
comparado com o valor da
count
no próximo objeto de estado
nextState.count
. Se eles são iguais
===
, o redesenho não ocorre e
false
retornado. Se eles não forem iguais,
true
retornado e um renderizador será iniciado para exibir o novo valor.
Se testarmos o código em um navegador, veremos um resultado familiar:

Mas, clicando no botão
Click Me
várias vezes, tudo o que vemos é o seguinte (exibido apenas uma vez!):
componentWillUpdate
componentDidUpdate

Você pode alterar o estado do componente TestC na guia React DevTools. Clique na guia React, selecione TestC à direita e você verá o valor do status do contador:

Este valor pode ser alterado. Clique no texto do contador, digite 2 e pressione Enter.

O estado da contagem mudará e, no console, veremos:
componentWillUpdate componentDidUpdate componentWillUpdate componentDidUpdate

O valor anterior era 1 e o novo era 2; portanto, era necessário um redesenho.
Vamos para o
componente puro .
O Pure Component apareceu em React na versão v15.5. É usado para comparar valores padrão (
change detection
). Com o
extend React.PureComponent
, você não precisa adicionar o método do ciclo de vida
shouldComponentUpdate
aos componentes: o rastreamento de alterações acontece por si só.
Adicione um PureComponent ao componente TestC.
import React from 'react'; class TestC extends React.PureComponent { constructor(props) { super(props); this.state = { count: 0 } } componentWillUpdate(nextProps, nextState) { console.log('componentWillUpdate') } componentDidUpdate(prevProps, prevState) { console.log('componentDidUpdate') } render() { return ( <div> { this.state.count } <button onClick = { () => this.setState({ count: 1 }) }> Click Me </button> </div > ); } } export default TestC;
Como você pode ver,
shouldComponentUpdate
em um comentário. Não precisamos mais dele: todo o trabalho é feito por
React.PureComponent
.
Reiniciando o navegador para testar a nova solução, e clicando no botão
Click Me
várias vezes, obtemos:


Como você pode ver, apenas um
component*Update
Entrada de
component*Update
apareceu no console.
Depois de ver como trabalhar em React com redesenho nas classes de componentes do ES6, passamos às funções de componentes. Como alcançar os mesmos resultados com eles?
Componentes de Função
Já sabemos como otimizar o trabalho com classes usando o Pure Component e o
shouldComponentUpdate
ciclo de vida
shouldComponentUpdate
. Ninguém argumenta que os componentes de classe são os principais componentes do React, mas você pode usar as funções como componentes.
function TestC(props) { return ( <div> I am a functional component </div> ) }
É importante lembrar que os componentes de função, diferentemente dos componentes de classe, não têm estado (embora agora os ganchos
useState
tenham
useState
, isso possa ser discutido), o que significa que não podemos configurar sua repintura. Os métodos de ciclo de vida que usamos durante o trabalho com classes não estão disponíveis aqui. Se pudermos adicionar ganchos de ciclo de vida aos componentes de função, podemos adicionar o método
shouldComponentUpdate
para informar ao React que um representante de função é necessário. (Talvez, na última frase, o autor tenha cometido um erro factual. - Aprox. Ed.) E, é claro, não podemos usar o
extend React.PureComponent
.
Transformamos nossa classe de componente ES6 TestC em uma função de componente.
import React from 'react'; const TestC = (props) => { console.log(`Rendering TestC :` props) return ( <div> {props.count} </div> ) } export default TestC;
Após renderizar no console, vemos a entrada
Rendering TestC :5
.

Abra o DevTools e clique na guia React. Aqui, tentaremos alterar o valor das propriedades do componente TestC. Selecione TestC, e as propriedades do contador com todas as propriedades e valores de TestC serão abertas à direita. Vemos apenas o contador com o valor atual de 5.
Clique no número 5 para alterar o valor. Uma janela de entrada será exibida.

Se alterarmos o valor numérico e pressionar Enter, as propriedades do componente serão alteradas de acordo com o valor que inserimos. Suponha que em 45.

Vá para a guia Console.

O componente TestC foi redesenhado porque o valor anterior de 5 mudou para o atual - 45. Volte à guia React e altere o valor para 45, depois volte ao Console.

Como você pode ver, o componente é redesenhado novamente, embora os valores anteriores e novos sejam os mesmos. :(
Como gerenciar um renderizador?
Solução: React.memo ()
React.memo()
é um novo recurso introduzido no React v16.6. Seu princípio de operação é semelhante ao princípio de
React.PureComponent
: ajuda no gerenciamento do redesenho de funções de componentes.
React.memo(...)
para componentes de classe é
React.PureComponent
para componentes de função.
Como trabalhar com React.memo (...)?Bem simples. Digamos que temos uma função componente.
const Funcomponent = ()=> { return ( <div> Hiya!! I am a Funtional component </div> ) }
Só precisamos passar o FuncComponent como argumento para a função React.memo.
const Funcomponent = ()=> { return ( <div> Hiya!! I am a Funtional component </div> ) } const MemodFuncComponent = React.memo(FunComponent)
React.memo retorna MemodFuncComponent
purified MemodFuncComponent
. É isso que desenharemos na marcação JSX. Quando as propriedades e o estado de um componente são alterados, o React compara as propriedades e os estados anteriores e atuais do componente. E somente se eles não forem idênticos, a função do componente será redesenhada.
Aplique isso ao componente de função TestC.
let TestC = (props) => { console.log('Rendering TestC :', props) return ( <div> { props.count } </> ) } TestC = React.memo(TestC);
Abra um navegador e baixe o aplicativo. Abra o DevTools e vá para a guia React. Selecione
<Memo(TestC)>
.
Se no bloco à direita alterarmos as propriedades do contador para 89, o aplicativo será redesenhado.

Se mudarmos o valor para o anterior, 89, então ...

Não haverá redesenho!
Glória a React.memo (...)! :)
Sem usar
React.memo(...)
em nosso primeiro exemplo, a função do componente TestC é redesenhada mesmo quando o valor anterior muda para o idêntico. Agora, graças a
React.memo(...)
, podemos evitar a renderização desnecessária das funções do componente.
Conclusão
- Vamos percorrer a lista?
React.PureComponent
- prata;React.memo(...)
- ouro;React.PureComponent
trabalha com classes ES6;React.memo(...)
trabalha com funções;React.PureComponent
otimiza o redesenho das classes ES6;React.memo(...)
otimiza o redesenho de funções;- a otimização de recursos é uma ótima idéia;
React
nunca mais será a mesma.
Se você tiver alguma dúvida sobre o artigo ou informações adicionais, alterações ou objeções, não hesite em
me escrever comentários, emails ou mensagens privadas.
Obrigada