- Supongamos que tengo una clase React P, que representa dos clases secundarias, C1 y C2.
- C1 contiene un campo de entrada. Me referiré a este campo de entrada como Foo.
- Mi objetivo es dejar que C2 reaccione a los cambios en Foo.
Se me ocurrieron dos soluciones, pero ninguna de ellas se siente del todo bien.
Primera solución
- Asignar P un estado,
state.input
. - Cree una
onChange
función en P, que toma un evento y establecestate.input
. - Pase esto
onChange
a C1 como aprops
, y deje que C1 se unathis.props.onChange
alonChange
Foo.
Esto funciona. Cada vez que cambia el valor de Foo, se activa a setState
en P, por lo que P tendrá la entrada para pasar a C2.
Pero no se siente del todo bien por la misma razón: estoy configurando el estado de un elemento padre a partir de un elemento hijo. Esto parece traicionar el principio de diseño de React: flujo de datos de una sola dirección.
¿Es así como se supone que debo hacerlo, o hay una solución más React-natural?
Segunda solución:
Solo pon a Foo en P.
Pero, ¿es este un principio de diseño que debo seguir al estructurar mi aplicación, colocando todos los elementos del formulario en la render
clase de más alto nivel?
Al igual que en mi ejemplo, si tengo una gran representación de C1, realmente no quiero poner el conjunto render
de C1 a render
P solo porque C1 tiene un elemento de forma.
¿Cómo debería hacerlo?
Respuestas:
Entonces, si te entiendo correctamente, ¿tu primera solución sugiere que mantienes el estado en tu componente raíz? No puedo hablar por los creadores de React, pero en general, encuentro que esta es una solución adecuada.
Mantener el estado es una de las razones (al menos eso creo) de que se creó React. Si alguna vez ha implementado su propio patrón de estado del lado del cliente para lidiar con una interfaz de usuario dinámica que tiene muchas piezas móviles interdependientes, entonces le encantará Reaccionar, porque alivia mucho este dolor de administración del estado.
Al mantener el estado más arriba en la jerarquía y actualizarlo a través de eventos, su flujo de datos sigue siendo bastante unidireccional, solo está respondiendo a eventos en el componente raíz, realmente no está obteniendo los datos allí a través de un enlace bidireccional, le está diciendo al componente Root que "oye, algo sucedió aquí abajo, revisa los valores" o estás pasando el estado de algunos datos en el componente hijo para actualizar el estado. Cambió el estado en C1 y desea que C2 lo tenga en cuenta, por lo tanto, al actualizar el estado en el componente raíz y volver a renderizar, los accesorios de C2 ahora están sincronizados ya que el estado se actualizó en el componente raíz y se transmitió .
fuente
C2
tiene ungetInitialState
for for data y dentro derender
élthis.state.data
?Habiendo usado React para construir una aplicación ahora, me gustaría compartir algunas ideas sobre esta pregunta que hice hace medio año.
Te recomiendo que leas
La primera publicación es extremadamente útil para comprender cómo debe estructurar su aplicación React.
Flux responde a la pregunta de por qué debería estructurar su aplicación React de esta manera (en lugar de cómo estructurarla). React es solo el 50% del sistema, y con Flux puedes ver la imagen completa y ver cómo constituyen un sistema coherente.
De vuelta a la pregunta.
En cuanto a mi primera solución, está totalmente bien dejar que el controlador vaya en la dirección inversa, ya que los datos siguen yendo en una sola dirección.
Sin embargo, si permitir que un controlador active un setState en P puede ser correcto o incorrecto dependiendo de su situación.
Si la aplicación es un simple convertidor Markdown, C1 es la entrada sin procesar y C2 es la salida HTML, está bien permitir que C1 active un setState en P, pero algunos podrían argumentar que esta no es la forma recomendada de hacerlo.
Sin embargo, si la aplicación es una lista de tareas, C1 ser la entrada para la creación de un nuevo TODO, C2 la lista de tareas en HTML, es probable que desee manejador para ir hasta dos niveles de P - a la
dispatcher
que dejó que elstore
actualización de ladata store
, que luego envían los datos a P y pueblan las vistas. Ver ese artículo de Flux. Aquí hay un ejemplo: Flux - TodoMVCEn general, prefiero la forma descrita en el ejemplo de la lista de tareas pendientes. Cuanto menos estado tenga en su aplicación, mejor.
fuente
Cinco años después, con la introducción de React Hooks, ahora hay una forma mucho más elegante de hacerlo con useContext hook.
Defina el contexto en un ámbito global, exporte variables, objetos y funciones en el componente principal y luego ajuste los elementos secundarios en la aplicación en un contexto proporcionado e importe lo que necesite en los componentes secundarios. A continuación se muestra una prueba de concepto.
Puede ejecutar este ejemplo en el editor de Code Sandbox.
fuente
La primera solución, con mantener el estado en el componente principal , es la correcta . Sin embargo, para problemas más complejos, debe pensar en alguna biblioteca de administración de estado , redux es el más popular utilizado con react.
fuente
Me sorprende que no haya respuestas con una solución React idiomática directa en el momento en que estoy escribiendo. Así que aquí está el uno (compare el tamaño y la complejidad con otros):
Cualquier control
input
(forma idiomática de trabajar con formularios en React) actualiza el estado principal en suonChange
devolución de llamada y aún no traiciona nada.Mire cuidadosamente el componente C1, por ejemplo. ¿Ve alguna diferencia significativa en la forma
C1
en que uninput
componente integrado maneja los cambios de estado? No deberías, porque no hay ninguno. Levantar el estado y pasar pares valor / onChange es idiomático para React sin procesar. No uso de referencias, como sugieren algunas respuestas.fuente
this.state
, faltaba el retorno en el renderizado y varios componentes deben estar envueltos en div o algo así. No sé cómo me perdí eso cuando escribí la respuesta original. Debe haber sido el error de edición.Respuesta más reciente con un ejemplo, que utiliza
React.useState
Mantener el estado en el componente principal es la forma recomendada. El padre debe tener acceso a él, ya que lo gestiona a través de dos componentes secundarios. No se recomienda moverlo al estado global, como el administrado por Redux, por la misma razón por la cual la variable global es peor que la local en general en ingeniería de software.
Cuando el estado está en el componente padre, el niño puede mutarlo si el padre le da al niño
value
y alonChange
manejador en accesorios (a veces se llama enlace de valor o patrón de enlace de estado ). Así es como lo haría con ganchos:Todo el componente principal se volverá a representar en el cambio de entrada en el elemento secundario, lo que podría no ser un problema si el componente principal es pequeño / rápido de volver a representar. El rendimiento de representación del componente principal todavía puede ser un problema en el caso general (por ejemplo, formularios grandes). Este es un problema resuelto en su caso (ver más abajo).
El patrón de enlace de estado y la reproducción sin padre son más fáciles de implementar usando la biblioteca de terceros, como Hookstate , sobrealimentada
React.useState
para cubrir una variedad de casos de uso, incluido el suyo. (Descargo de responsabilidad: soy un autor del proyecto).Así es como se vería con Hookstate.
Child1
cambiará la entrada,Child2
reaccionará a ella.Parent
mantendrá el estado pero no se volverá a procesar en el cambio de estado, soloChild1
y loChild2
hará.PD: hay muchos más ejemplos aquí que cubren escenarios similares y más complicados, incluidos datos profundamente anidados, validación de estado, estado global con
setState
gancho, etc. También hay una aplicación de muestra completa en línea , que utiliza el Hookstate y la técnica explicada anteriormente.fuente
Debería aprender la biblioteca Redux y ReactRedux. Estructurará sus estados y accesorios en una tienda y podrá acceder a ellos más adelante en sus componentes.
fuente
Con React> = 16.3 puede usar ref y forwardRef, para obtener acceso al DOM del niño desde su padre. No uses más los viejos métodos de referencia.
Aquí está el ejemplo usando su caso:
Consulte Refs y ForwardRef para obtener información detallada sobre las referencias y forwardRef.
fuente
shouldComponentUpdate(nextProps, nextState)
El siguiente código utiliza
@bound
anotaciones de ES.Nextbabel-plugin-transform-decorators-legacy
de BabelJS 6 y propiedades de clase (la anotación establece este valor en funciones miembro similares a bind):fuente
Se explica el concepto de pasar datos de padres a hijos y viceversa.
fuente