Como você decide, como escolhe entre esses três com base no propósito / tamanho / adereços / comportamento de nossos componentes?
Estender de React.PureComponentou para React.Componentum shouldComponentUpdatemétodo personalizado tem implicações no desempenho. O uso de componentes funcionais sem estado é uma opção "arquitetural" e ainda não possui benefícios de desempenho prontos para uso.
Para componentes simples, apenas para apresentação, que precisam ser reutilizados com facilidade, prefira componentes funcionais sem estado. Dessa forma, você tem certeza de que eles são dissociados da lógica real do aplicativo, que são fáceis de testar e que não têm efeitos colaterais inesperados. A exceção é se, por algum motivo, você tiver muitos deles ou se realmente precisar otimizar o método de renderização (como não é possível definir shouldComponentUpdateum componente funcional sem estado).
Estenda PureComponentse você souber que sua saída depende de props / state simples ("simples" significa que não há estruturas de dados aninhadas, pois o PureComponent realiza uma comparação superficial) E você precisa / pode obter algumas melhorias de desempenho.
Estenda Componente implemente você mesmo shouldComponentUpdatese precisar de alguns ganhos de desempenho, executando uma lógica de comparação personalizada entre adereços próximos / atuais e estado. Por exemplo, você pode executar rapidamente uma comparação profunda usando lodash # isEqual:
class MyComponent extends Component {
shouldComponentUpdate (nextProps, nextState) {
return !_.isEqual(this.props, nextProps) || !_.isEqual(this.state, nextState);
}
}
Além disso, implementar otimizações próprias shouldComponentUpdateou ampliadas PureComponentsão otimizações e, como de costume, você deve começar a investigar isso apenas se tiver problemas de desempenho ( evite otimizações prematuras ). Como regra geral, eu sempre tento fazer essas otimizações depois que o aplicativo está em um estado funcional, com a maioria dos recursos já implementados. É muito mais fácil focar nos problemas de desempenho quando eles realmente atrapalham.
Mais detalhes
Componentes apátridas funcionais:
Estes são definidos apenas usando uma função. Como não há estado interno para um componente sem estado, a saída (que é renderizada) depende apenas dos objetos fornecidos como entrada para esta função.
Prós:
A maneira mais simples possível de definir um componente no React. Se você não precisa gerenciar nenhum estado, por que se preocupar com classes e herança? Uma das principais diferenças entre uma função e uma classe é que, com a função, você tem certeza de que a saída depende apenas da entrada (não do histórico das execuções anteriores).
Idealmente, no seu aplicativo, você deve ter o maior número possível de componentes sem estado, porque isso normalmente significa que você moveu sua lógica para fora da camada de visualização e a moveu para algo como redux, o que significa que você pode testar sua lógica real sem precisar renderizar nada (muito mais fácil de testar, mais reutilizável etc.).
Contras:
Nenhum método de ciclo de vida. Você não tem como definir componentDidMounte outros amigos. Normalmente, você faz isso em um componente pai mais alto na hierarquia para poder transformar todos os filhos em sem estado.
Não há como controlar manualmente quando uma nova renderização é necessária, pois você não pode definir shouldComponentUpdate. Uma nova renderização acontece toda vez que o componente recebe novos adereços (nenhuma maneira de comparação superficial etc.). No futuro, o React poderá otimizar automaticamente os componentes sem estado, por enquanto existem algumas bibliotecas que você pode usar. Como componentes sem estado são apenas funções, basicamente é o problema clássico da "memorização de funções".
Não há suporte para referências: https://github.com/facebook/react/issues/4936
Um componente que estende a classe PureComponent VS Um componente normal que estende a classe Component:
Reagir costumava ter um que PureRenderMixinvocê poderia anexar a uma classe definida usando React.createClasssintaxe. O mixin simplesmente definiria uma shouldComponentUpdatecomparação superficial entre os próximos objetos e o próximo estado para verificar se alguma coisa mudou. Se nada mudar, não será necessário executar uma nova renderização.
Se você deseja usar a sintaxe ES6, não pode usar mixins. Portanto, por conveniência, o React introduziu uma PureComponentclasse da qual você pode herdar em vez de usar Component. PureComponentapenas implementa shouldComponentUpdateda mesma maneira que o PureRendererMixin. É principalmente uma questão de conveniência, para que você não precise implementá-lo por conta própria, pois uma comparação superficial entre o estado atual / próximo e os adereços é provavelmente o cenário mais comum que pode oferecer ganhos rápidos de desempenho.
Exemplo:
class UserAvatar extends Component {
render() {
return <div><img src={this.props.imageUrl} /> {{ this.props.username }} </div>
}
}
Como você pode ver, a saída depende de props.imageUrle props.username. Se em um componente pai você renderizar <UserAvatar username="fabio" imageUrl="http://foo.com/fabio.jpg" />com os mesmos adereços, o React chamariarender toda vez, mesmo que a saída seja exatamente a mesma. Lembre-se, no entanto, que o React implementa o dom diffing, para que o DOM não seja realmente atualizado. Ainda assim, executar o dom diffing pode ser caro, portanto, nesse cenário, seria um desperdício.
Se o UserAvatarcomponente se estender PureComponent, é realizada uma comparação superficial. E como props e nextProps são os mesmos, rendernão serão chamados.
Notas sobre a definição de "puro" no React:
Em geral, uma "função pura" é uma função que avalia sempre o mesmo resultado, com a mesma entrada. A saída (para React, é o que é retornado pelo rendermétodo) não depende de nenhum histórico / estado e não possui efeitos colaterais (operações que alteram o "mundo" fora da função).
No React, os componentes sem estado não são necessariamente componentes puros de acordo com a definição acima, se você chamar "sem estado" um componente que nunca chama this.setStatee que não usa this.state.
De fato, em a PureComponent, você ainda pode executar efeitos colaterais durante os métodos do ciclo de vida. Por exemplo, você pode enviar uma solicitação ajax para dentro componentDidMountou executar algum cálculo do DOM para ajustar dinamicamente a altura de uma div dentro render.
A definição de "componentes mudos" tem um significado mais "prático" (pelo menos no meu entendimento): um componente idiota "é informado" do que fazer por um componente pai por meio de adereços e não sabe como fazer as coisas, mas usa adereços retornos de chamada.
Exemplo de um "inteligente" AvatarComponent:
class AvatarComponent extends Component {
expandAvatar () {
this.setState({ loading: true });
sendAjaxRequest(...).then(() => {
this.setState({ loading: false });
});
}
render () {
<div onClick={this.expandAvatar}>
<img src={this.props.username} />
</div>
}
}
Exemplo de um "burro" AvatarComponent:
class AvatarComponent extends Component {
render () {
<div onClick={this.props.onExpandAvatar}>
{this.props.loading && <div className="spinner" />}
<img src={this.props.username} />
</div>
}
}
No final, eu diria que "burro", "sem estado" e "puro" são conceitos bem diferentes que às vezes podem se sobrepor, mas não necessariamente, dependendo principalmente do seu caso de uso.