shouldcomponentupdate react example performance reactjs ecmascript-6 destructuring

performance - example - React: parámetros predeterminados de Props vs ES6 al desestructurar(problemas de rendimiento)



react router (2)

Hablé con varias personas en el canal Discord #reactiflux y obtuve la respuesta que estaba buscando.

Básicamente, hay tres casos de uso con componentes React, y en algunos de ellos, la desestructuración de parámetros afectará el rendimiento, por lo que es importante entender lo que está pasando en la campana.

Componente funcional sin estado

const MyComponent = ({ name = ''John Doe'', displayName = humanize(name), address = helper.getDefaultAddress() }) => { return ( <div>{displayName}</div> ); };

Este es un componente funcional, sin estado. No hay estado y es funcional porque no es una instancia de Class , sino una función simple.

En este caso, no hay ciclo de vida, no puede tener un componentWillMount o shouldComponentUpdate o constructor allí. Y como no hay una gestión del ciclo de vida, no hay impacto en el rendimiento en absoluto. Este código es perfectamente válido. Es posible que algunos prefieran manejar el valor predeterminado de la displayName dentro del cuerpo de la función, pero al final no importa, no afectará el rendimiento.

Componente no funcional sin estado

(¡No hagas esto!)

class MyComponent extends React.Component { render() { const { name = ''John Doe'', displayName = humanize(name), address = helper.getDefaultAddress() } = this.props; return ( <div>{displayName}</div> ); } }

Este es un componente no funcional sin estado. No hay estado, pero no es "funcional" ya que es una class . Y debido a que es una clase que extiende React.Component , significa que tendrá un ciclo de vida. Puede tener componentWillMount o shouldComponentUpdate o constructor allí.

Y, debido a que tiene un ciclo de vida, la forma de escribir este componente es mala . ¿Pero por qué?

En pocas palabras, React ofrece un atributo defaultProps , para tratar con los valores de defaultProps predeterminados. Y, en realidad, es mejor usarlo cuando se trata de componentes no funcionales, ya que todos los métodos que se basan en esto lo this.props .

El fragmento de código anterior crea nuevas variables locales llamadas name y displayName , ¡pero los valores predeterminados se aplican solo para este método de render ! . Si desea que se apliquen los valores predeterminados para todos los métodos, como los del ciclo de vida React ( shouldComponentUpdate , etc.), entonces debe usar los defaultProps .

Por lo tanto, el código anterior es en realidad un error que puede llevar a malentendidos sobre el valor predeterminado del name .

Aquí es cómo debe escribirse en su lugar, para obtener el mismo comportamiento:

class MyComponent extends React.Component { render() { const { name, displayName = humanize(name), address } = this.props; return ( <div>{displayName}</div> ); } } MyComponent.defaultProps = { name: ''John Doe'', address: helper.getDefaultAddress(), };

Este es mejor. Porque el nombre siempre será John Doe si no fue definido. También se trató el valor predeterminado de la address , pero no la imagen ... ¿Por qué?

Bueno, todavía no he encontrado una manera de evitar ese caso de uso especial. Debido a que la displayName debe basarse en la propiedad de name , a la que no podemos acceder (AFAIK) al definir los defaultProps . La única manera que veo es lidiar con ello en el método de render directamente. Tal vez hay una mejor manera.

No tenemos este problema con la propiedad de la address , ya que no se basa en las propiedades de MyComponent, sino que depende de algo totalmente independiente que no necesita los accesorios.

Componente no funcional con estado

Funciona exactamente igual que "Componente no funcional sin estado". Debido a que todavía hay un ciclo de vida, el comportamiento será el mismo. El hecho de que haya un state interno adicional en el componente no cambiará nada.

Espero que esto ayude a entender cuando se utiliza la desestructuración con componentes. Realmente me gusta la forma funcional, es mucho más limpio que el IMHO (+1 por simplicidad).

Es posible que prefiera usar siempre los resultados defaultProps , ya sea que trabaje con componentes funcionales o no funcionales, también es válido. (+1 por consistencia)

Solo tenga en cuenta el ciclo de vida de los componentes no funcionales que "requieren" el uso de los defaultProps . Pero al final la elección es siempre tuya;)

Acabo de encontrar una pregunta sobre los rendimientos de React cuando configuro valores predeterminados en uno de mis componentes funcionales sin estado .

Este componente tenía un valor defaultProps que definía la row: false , pero no me gustó porque el valor defaultProps es el final del archivo, lo que hace que sea más difícil verlo. Y por lo tanto, no somos conscientes de la propiedad por defecto. Así que lo moví directamente a la declaración de función y lo asigné usando el valor predeterminado de ES6 para los parámetros.

const FormField = ({ row = false, ...others, }) => { // logic... };

Pero luego discutimos con un compañero de trabajo acerca de si esto es una buena idea o no . Debido a que hacerlo puede parecer trivial, pero también puede tener un gran impacto en las actuaciones, ya que reaccionar no es consciente del valor predeterminado.

Creo que en este caso, es trivial. Porque es un valor booleano y no un objeto / matriz y, por lo tanto, no se verá como un valor diferente durante la reconciliación .

Pero, ahora veamos un caso de uso más avanzado:

const FormField = ({ input: { name, value, ...inputRest }, label = capitalize(name), placeholder = label, row = false, meta: { touched, error, warning }, ...others, }) => { // logic... };

Aquí, baso el valor del placeholder de placeholder de la label , que a su vez se basa en input.name . El uso de la desestructuración de ES6 con los valores predeterminados para los parámetros hace que todo sea muy fácil de escribir / entender y funciona como un encanto.

¿Pero es una buena idea? Y si no, ¿cómo lo harías correctamente?


Mirando el caso de uso avanzado que tiene, está agregando propiedades innecesarias al componente. label y el placeholder dependen de otras propiedades que se pasen y, en mi opinión, no deben aparecer como un parámetro del componente en sí.

Si estuviera tratando de usar <FormField /> en mi aplicación y tuviera que buscar para ver qué dependencias tiene ese componente específico, estaría un poco confundido en cuanto a por qué está creando parámetros que se basan en otros parámetros. Movería la label y el placeholder en el cuerpo de la función para que quede claro que no son dependencias de componentes sino simplemente efectos secundarios.

En lo que respecta al rendimiento aquí, no estoy seguro de que haya una diferencia significativa en ambos sentidos. Los componentes sin estado realmente no tienen una ''instancia de respaldo'' que tienen los componentes con estado, lo que significa que no hay un objeto en memoria que realiza un seguimiento del componente. Creo que es solo una función pura de pasar parámetros y devolver la vista.

En esa misma nota ... agregar los PropTypes ayudará con la verificación de tipos.

const FormField = ({ input: { name, value, ...inputRest }, row = false, meta: { touched, error, warning }, ...others, }) => { const label = capitalize(name), const placeholder = label, return ( // logic ); }; FormField.propTypes = { input: PropTypes.shape({ name: PropTypes.string.isRequired, value: PropTypes.string, }).isRequired, meta: PropTypes.shape({ touched: PropTypes.bool.isRequired, error: PropTypes.bool.isRequired, warning: PropTypes.bool.isRequired, }).isRequired, row: PropTypes.bool.isRequired, };