javascript - pagina - Implicaciones de rendimiento de la implementación de enlace de datos bidireccional en React
react js (1)
Implicaciones de enlace de datos de 2 vías
A partir de la primera parte de su pregunta, existen dos razones principales para que la reacción no se realice con un enlace de datos bidireccional:
- Una única fuente de verdad para los cambios de datos en una aplicación React, por lo tanto, hay menos posibilidades de errores y una depuración más sencilla
- Beneficios de rendimiento
En React, podemos compartir el estado entre diferentes componentes secundarios elevando el estado a un componente principal común. Cuando se actualiza una parte del estado compartido, todos los componentes secundarios pueden actualizarse ellos mismos. Here hay un buen ejemplo de la documentación relacionada con los formularios.
Hablando de los beneficios de rendimiento, el enlace de datos bidireccional en otro contexto (como AngularJS) funciona mediante observadores que observan diferentes elementos. Esto suena más fácil (y menos código que el flujo de datos unidireccional de React) para un pequeño número de elementos, sin embargo, a medida que aumenta el número de componentes / elementos de su interfaz de usuario, también lo hace el número de observadores. Un solo cambio en este caso hace que muchos observadores se enciendan para mantener las cosas sincronizadas. Esto hace que el rendimiento sea un poco lento. En el caso de React, dado que solo hay una forma de flujo de datos, es más fácil determinar qué componentes deben actualizarse.
Manejo de actualizaciones de estado
Llegando a la segunda parte de su pregunta, su biblioteca de estado proporciona los datos a los componentes de su formulario, lo que hace que los componentes dependientes se actualicen en el cambio de estado. Aquí están mis pensamientos:
Estaba pensando en permitir que los campos individuales dejaran de lado ese comportamiento en caso de que el programador estuviera preocupado por el rendimiento, pero luego comencé a preguntarme cuándo sería un verdadero problema de rendimiento.
La actualización de la tienda en sí misma sucederá bastante rápido. JavaScript se ejecuta muy rápido, las actualizaciones de DOM son las que a menudo causan cuellos de botella. Por lo tanto, a menos que haya cientos de elementos de formulario dependientes en la misma página y todos ellos se actualicen, todo estará bien.
Y supongamos que no estaba usando apollo, sino que solo llamaba a una función que actualiza directamente alguna tienda global. ¿Cuál sería la consideración de rendimiento entonces?
No creo que tenga una diferencia significativa.
Mi pensamiento es que si un formulario va a admitir la actualización inmediata del estado del formulario a medida que el usuario escribe en un campo, también podría hacerlo para todos los campos. El usuario solo puede escribir un campo a la vez, y no veo el beneficio de hacer que la página sea más rápida (probablemente de manera despreciable) con algunos campos y, a veces, más lenta con otros.
De acuerdo con esto.
Mi biblioteca les permite a los consumidores usar cualquier componente de entrada que deseen, por lo que si el programador solo quiere menos actualizaciones de estado, podría simplemente escribir un componente que denuncia el evento OnChange de React o que use el propio evento de cambio o desenfoque del navegador.
Creo que la mayoría de los casos de uso se resolverían con una simple input
. Una vez más, no veo un beneficio de rendimiento con menos actualizaciones de estado aquí. La denuncia podría ser útil si, por ejemplo, estoy ejecutando una llamada a la API en la entrada (y quiero esperar antes de que el usuario deje de escribir).
¿Hay alguna otra razón por la cual un usuario de mi biblioteca querría ignorar los cambios para campos particulares hasta que el usuario envíe el formulario? ¿O tal vez una opción más útil sería ignorar los cambios para todo el formulario (hasta que se envíe)?
No veo un beneficio en ignorar los cambios para un campo en particular o esperar hasta enviar. Por otro lado, cuando utilizo formularios, un caso de uso común con el que me encuentro implementando cosas es la validación de datos. Por ejemplo,
- Proporcionar comentarios al usuario cuando esté creando una contraseña.
- verifica si un correo electrónico es válido
- realizar llamadas a la API para ver si un nombre de usuario es válido, etc.
Estos casos necesitarían que el estado se actualice a medida que el usuario escribe.
tl; dr
Debería estar bien con el estado de actualización ya que el usuario está escribiendo. Si aún está preocupado por el rendimiento, le sugeriría que perfilara sus componentes para aislar los cuellos de botella, si los hubiera :)
Una pregunta común de los recién llegados a React es por qué el enlace de datos bidireccional no es una característica integrada, y la respuesta habitual incluye una explicación del flujo de datos unidireccional junto con la idea de que el enlace de datos bidireccional no siempre es deseable por razones de rendimiento . Es el segundo punto que me gustaría entender con más detalle.
Actualmente estoy trabajando en una biblioteca de formularios para apollo-link-state (una nueva herramienta de administración de estado del lado del cliente de Apollo). El concepto es muy similar a redux-form, excepto que se usa apollo-link-state en lugar de redux como administrador estatal. (Tenga en cuenta que el estado del formulario se almacena por separado del estado de las entidades del dominio, aunque una entidad se puede usar opcionalmente para completar el estado inicial de un formulario).
Cuando el usuario realiza cambios en el formulario, la biblioteca actualiza inmediatamente la tienda a través de los controladores onChange
. Estaba pensando en permitir que los campos individuales dejaran de lado ese comportamiento en caso de que el programador estuviera preocupado por el rendimiento, pero luego comencé a preguntarme cuándo sería un verdadero problema de rendimiento. El navegador disparará el evento oninput
sin importar qué, así que la única consideración de rendimiento que se me ocurre es si la tienda se actualiza o no según el tipo de usuario. Concedido, existe la sobrecarga adicional de ejecutar una mutación en lugar de solo llamar a setState()
, pero eso básicamente equivale a un par de llamadas a funciones adicionales. Y supongamos que no estaba usando apollo, sino que solo llamaba a una función que actualiza directamente alguna tienda global. ¿Cuál sería la consideración de rendimiento entonces?
Mi pensamiento es que si un formulario va a admitir la actualización inmediata del estado del formulario a medida que el usuario escribe en un campo, también podría hacerlo para todos los campos. El usuario solo puede escribir un campo a la vez, y no veo el beneficio de hacer que la página sea más rápida (probablemente despreciable) con algunos campos y, a veces, más lenta con otros. Además, mi biblioteca les permite a los consumidores usar cualquier componente de entrada que deseen, por lo que si el programador solo quiere menos actualizaciones de estado, podría simplemente escribir un componente que denuncia el evento OnChange de React o usa el evento de change
o blur
propio del navegador.
¿Me estoy perdiendo de algo? ¿Hay alguna otra razón por la cual un usuario de mi biblioteca querría ignorar los cambios para campos particulares hasta que el usuario envíe el formulario? ¿O tal vez una opción más útil sería ignorar los cambios en todo el formulario (hasta que se envíe)?
Aquí hay una ilustración básica (muy simplificada) del concepto básico detrás de mi enfoque actual:
// defined in a globally-accessible module
const formState = {
// This somehow causes any dependent form components to re-render
// when state changes
update(formName, updatedState) {
...
}
}
export default formState
...
// UserForm.js:
export default class UserForm extends PureComponent {
componentDidMount() {
formState.userForm = {
firstName: '''',
lastName: '''',
}
}
handleChange(e) {
const { target } = e
formState.update(''userForm'', { [target.name]: target.value })
}
//...
render() {
const { userForm } = formState
return (
<form onSubmit={this.handleSubmit}>
<label for="name">Name</label>
<input id="name" type="text" onChange={this.handleChange} value={userForm.name} />
<label for="email">Email</label>
<input id="email" type="email" onChange={this.handleChange} value={userForm.email} />
</form>
)
}
}
Finalmente, en aras de la exhaustividad, debo mencionar que hay algunas consideraciones de diseño de API involucradas en esto también. Los componentes de entrada individuales podrían tener un diseño un poco más simple si no proporcionara una opción para excluirse del enlace automático de 2 vías. Puedo publicar detalles si alguien está interesado.