¿Cómo decide, cómo elige entre estos tres en función del propósito / tamaño / accesorios / comportamiento de nuestros componentes?
Extender desde React.PureComponent
o React.Component
con un shouldComponentUpdate
método personalizado tiene implicaciones de rendimiento. El uso de componentes funcionales sin estado es una opción "arquitectónica" y aún no tiene beneficios de rendimiento listos para usar.
Para componentes simples, solo presentacionales que necesitan ser reutilizados fácilmente, prefiera componentes funcionales sin estado. De esta manera, está seguro de que están desconectados de la lógica real de la aplicación, que son fáciles de probar y que no tienen efectos secundarios inesperados. La excepción es si por alguna razón tiene muchos de ellos o si realmente necesita optimizar su método de representación (ya que no puede definir shouldComponentUpdate
un componente funcional sin estado).
Extienda PureComponent
si sabe que su salida depende de accesorios / estado simples ("simple" significa que no hay estructuras de datos anidadas, ya que PureComponent realiza una comparación superficial) Y necesita / puede obtener algunas mejoras de rendimiento.
Extienda Component
e implemente el suyo shouldComponentUpdate
si necesita algunas mejoras de rendimiento al realizar una lógica de comparación personalizada entre los accesorios y el estado siguiente / actual. Por ejemplo, puede realizar rápidamente una comparación profunda usando lodash # isEqual:
class MyComponent extends Component {
shouldComponentUpdate (nextProps, nextState) {
return !_.isEqual(this.props, nextProps) || !_.isEqual(this.state, nextState);
}
}
Además, implementar las suyas propias shouldComponentUpdate
o ampliarlas PureComponent
son optimizaciones, y como de costumbre, debe comenzar a investigar eso solo si tiene problemas de rendimiento ( evite optimizaciones prematuras ). Como regla general, siempre trato de hacer estas optimizaciones después de que la aplicación está funcionando, con la mayoría de las características ya implementadas. Es mucho más fácil concentrarse en los problemas de rendimiento cuando realmente se interponen en el camino.
Más detalles
Componentes sin estado funcionales:
Estos se definen simplemente usando una función. Como no hay un estado interno para un componente sin estado, la salida (lo que se procesa) solo depende de los accesorios proporcionados como entrada para esta función.
Pros:
La forma más simple posible de definir un componente en React. Si no necesita administrar ningún estado, ¿por qué molestarse con las clases y la herencia? Una de las principales diferencias entre una función y una clase es que con la función está seguro de que la salida depende solo de la entrada (no de ningún historial de ejecuciones anteriores).
Idealmente en su aplicación, debe intentar tener tantos componentes sin estado como sea posible, porque eso normalmente significa que movió su lógica fuera de la capa de vista y la movió a algo como redux, lo que significa que puede probar su lógica real sin tener que renderizar nada (mucho más fácil de probar, más reutilizable, etc.).
Contras:
No hay métodos de ciclo de vida. No tienes una forma de definir componentDidMount
y otros amigos. Normalmente lo haces dentro de un componente padre más alto en la jerarquía para que puedas convertir a todos los hijos en apátridas.
No hay forma de controlar manualmente cuando se necesita una nueva representación, ya que no se puede definir shouldComponentUpdate
. Un renderizado ocurre cada vez que el componente recibe nuevos accesorios (no hay forma de comparar superficialmente, etc.). En el futuro, React podría optimizar automáticamente los componentes sin estado, por ahora hay algunas bibliotecas que puede usar. Dado que los componentes sin estado son solo funciones, básicamente es el problema clásico de la "memorización de funciones".
Las referencias no son compatibles: https://github.com/facebook/react/issues/4936
Un componente que extiende la clase PureComponent VS Un componente normal que extiende la clase Componente:
React solía tener un PureRenderMixin
que podía asociar a una clase definida usando la React.createClass
sintaxis. El mixin simplemente definiría una shouldComponentUpdate
realización de una comparación superficial entre los siguientes accesorios y el siguiente estado para verificar si algo ha cambiado. Si nada cambia, entonces no hay necesidad de realizar una nueva representación.
Si desea usar la sintaxis de ES6, no puede usar mixins. Entonces, por conveniencia, React introdujo una PureComponent
clase de la que puede heredar en lugar de usar Component
. PureComponent
solo se implementa shouldComponentUpdate
de la misma manera que el PureRendererMixin
. Es principalmente una cuestión de conveniencia, por lo que no tiene que implementarlo usted mismo, ya que una comparación superficial entre el estado actual / próximo y los accesorios es probablemente el escenario más común que le puede dar algunas ganancias rápidas de rendimiento.
Ejemplo:
class UserAvatar extends Component {
render() {
return <div><img src={this.props.imageUrl} /> {{ this.props.username }} </div>
}
}
Como puede ver, la salida depende de props.imageUrl
y props.username
. Si en un componente principal se procesa <UserAvatar username="fabio" imageUrl="http://foo.com/fabio.jpg" />
con los mismos accesorios, React llamará render
siempre, incluso si el resultado es exactamente el mismo. Sin embargo, recuerde que React implementa dom diffing, por lo que el DOM no se actualizaría realmente. Aún así, realizar la diferenciación de dom puede ser costoso, por lo que en este escenario sería un desperdicio.
Si el UserAvatar
componente se extiende en su PureComponent
lugar, se realiza una comparación superficial. Y debido a que los accesorios y nextProps son iguales, render
no se llamarán en absoluto.
Notas sobre la definición de "puro" en React:
En general, una "función pura" es una función que evalúa siempre el mismo resultado dada la misma entrada. La salida (para React, eso es lo que devuelve el render
método) no depende de ningún historial / estado y no tiene efectos secundarios (operaciones que cambian el "mundo" fuera de la función).
En React, los componentes sin estado no son necesariamente componentes puros según la definición anterior si llama "sin estado" a un componente que nunca llama this.setState
y que no utiliza this.state
.
De hecho, en a PureComponent
, aún puede realizar efectos secundarios durante los métodos del ciclo de vida. Por ejemplo, podría enviar una solicitud ajax dentro componentDidMount
o podría realizar algunos cálculos DOM para ajustar dinámicamente la altura de un div dentro render
.
La definición de "Componentes tontos" tiene un significado más "práctico" (al menos en mi entendimiento): un componente tonto "se le dice" qué hacer por un componente padre a través de accesorios, y no sabe cómo hacer las cosas, pero usa accesorios devoluciones de llamada en su lugar.
Ejemplo de un "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>
}
}
Ejemplo de un "tonto" AvatarComponent
:
class AvatarComponent extends Component {
render () {
<div onClick={this.props.onExpandAvatar}>
{this.props.loading && <div className="spinner" />}
<img src={this.props.username} />
</div>
}
}
Al final, diría que "tonto", "sin estado" y "puro" son conceptos muy diferentes que a veces pueden superponerse, pero no necesariamente, dependiendo principalmente de su caso de uso.