Acabo de comenzar con ReactJS y estoy un poco atascado en un problema que tengo.
Mi aplicación es esencialmente una lista con filtros y un botón para cambiar el diseño. Por el momento estoy usando tres componentes: <list />
, < Filters />
y <TopBar />
, ahora, obviamente, cuando cambio de configuración en el < Filters />
que quiero para desencadenar algún método de <list />
actualizar mi punto de vista.
¿Cómo puedo hacer que esos 3 componentes interactúen entre sí, o necesito algún tipo de modelo de datos global en el que pueda hacer cambios?
javascript
reactjs
woutr_be
fuente
fuente
Respuestas:
El mejor enfoque dependerá de cómo planee organizar esos componentes. Algunos ejemplos de escenarios que me vienen a la mente en este momento:
<Filters />
es un componente hijo de<List />
<Filters />
y<List />
son hijos de un componente padre<Filters />
y<List />
vivir en componentes raíz separados por completo.Puede haber otros escenarios en los que no estoy pensando. Si el tuyo no se ajusta a estos, avísame Aquí hay algunos ejemplos muy generales de cómo he estado manejando los dos primeros escenarios:
Escenario 1
Puede pasar un controlador de
<List />
a<Filters />
, que luego se puede llamar en elonChange
evento para filtrar la lista con el valor actual.JSFiddle para # 1 →
Escenario # 2
Similar al escenario # 1, pero el componente principal será el que pasará la función del controlador a
<Filters />
, y pasará la lista filtrada a<List />
. Me gusta más este método ya que desacopla el<List />
del<Filters />
.JSFiddle para # 2 →
Escenario # 3
Cuando los componentes no pueden comunicarse entre ningún tipo de relación padre-hijo, la documentación recomienda configurar un sistema de eventos global .
fuente
updateFilter
a<Filters />
y una matriz comoitems
a<List />
. Podrías usar esos componentes hijos en otros padres con diferentes comportamientos, ya sea juntos o solos. Por ejemplo, si desea mostrar una lista dinámica pero no necesita filtrado.Hay múltiples formas de hacer que los componentes se comuniquen. Algunos pueden ser adecuados para su caso de uso. Aquí hay una lista de algunos que he encontrado útiles para conocer.
Reaccionar
Comunicación directa padre / hijo
Aquí el componente hijo llamará a una devolución de llamada proporcionada por el padre con un valor, y el padre podrá obtener el valor proporcionado por los niños en el padre.
Si crea una función / página de su aplicación, es mejor tener un padre único que administre las devoluciones de llamada / estado (también llamado
container
osmart component
), y que todos los niños sean apátridas, solo informando cosas al padre. De esta manera, puede "compartir" fácilmente el estado del padre con cualquier hijo que lo necesite.Contexto
React Context permite mantener el estado en la raíz de la jerarquía de sus componentes y poder inyectar este estado fácilmente en componentes muy anidados, sin la molestia de tener que pasar accesorios a cada componente intermedio.
Hasta ahora, el contexto era una característica experimental, pero una nueva API está disponible en React 16.3.
El consumidor está utilizando el patrón de función render prop / children
Consulte esta publicación de blog para más detalles.
Antes de React 16.3, recomendaría usar react-broadcast, que ofrece una API bastante similar, y una API de contexto anterior.
Portales
Use un portal cuando desee mantener 2 componentes juntos para que se comuniquen con funciones simples, como en padre / hijo normal, pero no desea que estos 2 componentes tengan una relación padre / hijo en el DOM, porque de las restricciones visuales / CSS que implica (como el índice z, la opacidad ...).
En este caso puede usar un "portal". Existen diferentes bibliotecas de reacción que utilizan portales , generalmente utilizados para modales , ventanas emergentes, información sobre herramientas ...
Considera lo siguiente:
Podría producir el siguiente DOM cuando se representa en el interior
reactAppContainer
:Más detalles aquí
Tragamonedas
Define una ranura en algún lugar y luego llena la ranura desde otro lugar de su árbol de renderizado.
Esto es un poco similar a los portales, excepto que el contenido lleno se representará en un espacio que usted defina, mientras que los portales generalmente representan un nuevo nodo dom (a menudo un elemento secundario de document.body)
Verifique la biblioteca react-slot-fill
Bus de eventos
Como se indica en la documentación de React :
Hay muchas cosas que puede usar para configurar un bus de eventos. Puede crear una variedad de oyentes, y en la publicación del evento, todos los oyentes recibirían el evento. O puede usar algo como EventEmitter o PostalJs
Flujo
Flux es básicamente un bus de eventos, excepto que los receptores de eventos son tiendas. Esto es similar al sistema de bus de eventos básico, excepto que el estado se administra fuera de React
La implementación original de Flux se parece a un intento de hacer un abastecimiento de eventos de una manera hacky.
Redux es para mí la implementación de Flux que es la más cercana al abastecimiento de eventos, y beneficia muchas de las ventajas del abastecimiento de eventos, como la capacidad de viajar en el tiempo. No está estrictamente vinculado a React y también se puede usar con otras bibliotecas de vistas funcionales.
El video tutorial de Redhead de Egghead es realmente agradable y explica cómo funciona internamente (es realmente simple).
Cursores
Los cursores provienen de ClojureScript / Om y se usan ampliamente en proyectos React. Permiten administrar el estado fuera de React y permiten que múltiples componentes tengan acceso de lectura / escritura a la misma parte del estado, sin necesidad de saber nada sobre el árbol de componentes.
Existen muchas implementaciones, incluidas ImmutableJS , React-cursores y Omniscient
Editar 2016 : parece que las personas están de acuerdo en que los cursores funcionan bien para aplicaciones más pequeñas, pero no se ajustan bien en aplicaciones complejas. Om Next ya no tiene cursores (mientras que Om introdujo el concepto inicialmente)
Arquitectura de olmo
La arquitectura Elm es una arquitectura propuesta para ser utilizada por el lenguaje Elm . Incluso si Elm no es ReactJS, la arquitectura de Elm también se puede hacer en React.
Dan Abramov, el autor de Redux, hizo una implementación de la arquitectura Elm usando React.
Tanto Redux como Elm son realmente geniales y tienden a potenciar los conceptos de origen de eventos en la interfaz, lo que permite la depuración de viajes en el tiempo, deshacer / rehacer, reproducir ...
La principal diferencia entre Redux y Elm es que Elm tiende a ser mucho más estricto sobre la gestión del estado. En Elm no puede tener un estado de componente local o montar / desmontar ganchos y todos los cambios de DOM deben ser activados por cambios de estado globales. La arquitectura Elm propone un enfoque escalable que permite manejar TODO el estado dentro de un único objeto inmutable, mientras que Redux propone un enfoque que lo invita a manejar la MAYORÍA del estado en un solo objeto inmutable.
Si bien el modelo conceptual de Elm es muy elegante y la arquitectura permite escalar bien en aplicaciones grandes, en la práctica puede ser difícil o involucrar más repetitivo para lograr tareas simples como enfocar una entrada después de montarla o integrarse con una biblioteca existente con una interfaz imperativa (es decir, el complemento JQuery). Tema relacionado .
Además, la arquitectura Elm implica más código repetitivo. No es tan detallado o complicado de escribir, pero creo que la arquitectura Elm es más adecuada para los lenguajes de tipo estático.
FRP
Las bibliotecas como RxJS, BaconJS o Kefir se pueden usar para producir flujos FRP para manejar la comunicación entre componentes.
Puedes probar por ejemplo Rx-React
Creo que usar estas bibliotecas es bastante similar a usar lo que ofrece el lenguaje ELM con señales .
El marco de CycleJS no usa ReactJS pero usa vdom . Comparte muchas similitudes con la arquitectura Elm (pero es más fácil de usar en la vida real porque permite ganchos vdom) y usa RxJ ampliamente en lugar de funciones, y puede ser una buena fuente de inspiración si desea usar FRP con Reaccionar. Los videos de CycleJs Egghead son agradables de entender cómo funciona.
CSP
Los CSP (procesos secuenciales de comunicación) son populares actualmente (principalmente debido a Go / goroutines y core.async / ClojureScript), pero también puede usarlos en JavaScript con JS-CSP .
James Long ha hecho un video explicando cómo se puede usar con React.
Sagas
Una saga es un concepto de fondo que proviene del mundo DDD / EventSourcing / CQRS, también llamado "administrador de procesos". Está siendo popularizado por el proyecto redux-saga , principalmente como un reemplazo de redux-thunk para el manejo de efectos secundarios (es decir, llamadas API, etc.). La mayoría de las personas actualmente piensa que solo sirve para los efectos secundarios, pero en realidad se trata más de desacoplar componentes.
Es más un complemento de una arquitectura Flux (o Redux) que un sistema de comunicación totalmente nuevo, porque la saga emite acciones Flux al final. La idea es que si tiene widget1 y widget2, y desea que estén desacoplados, no puede disparar la acción de orientación widget2 desde widget1. Por lo tanto, hace que widget1 solo active acciones que se dirigen a sí mismo, y la saga es un "proceso en segundo plano" que escucha las acciones de widget1 y puede enviar acciones que se dirigen a widget2. La saga es el punto de acoplamiento entre los 2 widgets, pero los widgets permanecen desacoplados.
Si estás interesado mira mi respuesta aquí
Conclusión
Si desea ver un ejemplo de la misma pequeña aplicación que utiliza estos diferentes estilos, consulte las ramas de este repositorio .
No sé cuál es la mejor opción a largo plazo, pero realmente me gusta cómo se ve Flux como fuente de eventos.
Si no conoce los conceptos de abastecimiento de eventos, eche un vistazo a este blog muy pedagógico: dar la vuelta a la base de datos con apache Samza , es una lectura obligada para comprender por qué Flux es bueno (pero esto también podría aplicarse a FRP) )
Creo que la comunidad está de acuerdo en que la implementación de Flux más prometedora es Redux , que permitirá progresivamente una experiencia de desarrollo muy productiva gracias a la recarga en caliente. ¡Impresionante livecoding de ala Bret Victor's Inventing on Principle es posible!
fuente
De acuerdo, hay pocas formas de hacerlo, pero quiero centrarme exclusivamente en usar la tienda usando Redux, lo que hace que tu vida sea mucho más fácil para estas situaciones en lugar de darte una solución rápida solo para este caso, usar React puro terminará en problemas Una aplicación realmente grande y la comunicación entre componentes se vuelve cada vez más difícil a medida que la aplicación crece ...
Entonces, ¿qué hace Redux por ti?
Redux es como el almacenamiento local en su aplicación que se puede usar siempre que necesite datos para usar en diferentes lugares de su aplicación ...
Básicamente, la idea de Redux proviene de Flux originalmente, pero con algunos cambios fundamentales, incluido el concepto de tener una fuente de verdad al crear una sola tienda ...
Mire el gráfico a continuación para ver algunas diferencias entre Flux y Redux ...
Considere aplicar Redux en su aplicación desde el principio si su aplicación necesita comunicación entre Componentes ...
También puede ser útil leer estas palabras de la documentación de Redux para comenzar:
fuente
datepicker
(como componente) y ese componente se puede cargar desde varios componentes que viven en la misma página, ¿cómo sabría eldatepicker
componente qué Acción enviar a redux? Esta es la esencia del problema, unir una acción en un componente con otro y NO con ningún otro componente . (tenga en cuenta que eldatepicker
sí mismo es un componente profundo y profundo dentro del componente modal en sí)redux
qué puede almacenar, sino CÓMO pasar la acción en el fondo a lo que necesita desencadenarla. ¿Cómo sabe un componente profundo lo que EXACTAMENTE necesita ser activado? dado que en el ejemplo di un componente general que debería dispararse a un reductor específico, dependiendo del escenario, por lo que podría ser un reductor diferente ya que se puede usar un modal de selector de fecha para cualquier componente.Esta es la forma en que manejé esto.
Digamos que tiene una <seleccionar> para el mes y una <seleccionar> para el día . El número de días depende del mes seleccionado.
Ambas listas son propiedad de un tercer objeto, el panel izquierdo. Ambos <select> también son hijos del leftPanel <div>
Es un juego con las devoluciones de llamada y los controladores en el componente LeftPanel .
Para probarlo, simplemente copie el código en dos archivos separados y ejecute index.html . Luego seleccione un mes y vea cómo cambia la cantidad de días.
date.js
Y el HTML para ejecutar el componente del panel izquierdo index.html
fuente
Vi que la pregunta ya está respondida, pero si desea obtener más detalles, hay un total de 3 casos de comunicación entre componentes :
fuente
Extendiendo la respuesta de @MichaelLaCroix cuando un escenario es que los componentes no pueden comunicarse entre ningún tipo de relación padre-hijo, la documentación recomienda configurar un sistema de eventos global.
En el caso de
<Filters />
y<TopBar />
no tiene ninguna de las relaciones anteriores, un simple emisor global podría usarse así:componentDidMount
- Suscríbete al eventocomponentWillUnmount
- Darse de baja del eventoCódigo React.js y EventSystem
EventSystem.js
NotificationComponent.js
fuente
Existe tal posibilidad incluso si no son una relación Padre-Hijo, y eso es Flux. Hay una implementación bastante buena (para mí personalmente) para la llamada Alt.JS (con Alt-Container).
Por ejemplo, puede tener una barra lateral que depende de lo que se establece en los detalles del componente. La barra lateral de componentes está conectada con SidebarActions y SidebarStore, mientras que Details es DetailsActions y DetailsStore.
Podrías usar AltContainer así
Lo que mantendría las tiendas (bueno, podría usar "store" en lugar de "stores" prop). Ahora, {this.props.content} PUEDE SER Detalles dependiendo de la ruta. Digamos que / Detalles nos redirige a esa vista. Los detalles tendrían, por ejemplo, una casilla de verificación que cambiaría el elemento de la barra lateral de X a Y si se marcara.
Técnicamente no existe una relación entre ellos y sería difícil hacerlo sin flujo. PERO CON ESO es bastante fácil.
Ahora vamos a DetallesAcciones. Crearemos allí
y DetailsStore
Y ahora, este es el lugar donde comienza la magia.
Como puede ver, hay bindListener para SidebarActions.ComponentStatusChanged que se usará SI se usará setSiteComponent.
ahora en SidebarActions
Tenemos tal cosa. Despachará ese objeto en la llamada. Y se llamará si se usará setSiteComponent en la tienda (que puede usar en el componente, por ejemplo, durante onChange on Button o lo que sea)
Ahora en SidebarStore tendremos
Ahora aquí puedes ver que esperará a DetailsStore. Qué significa eso? más o menos significa que este método debe esperar a que DetailsStore se actualice para poder actualizarse.
tl; dr One Store está escuchando los métodos en una tienda y activará una acción desde la acción del componente, que actualizará su propia tienda.
Espero que pueda ayudarte de alguna manera.
fuente
Si desea explorar las opciones de comunicación entre componentes y siente que cada vez es más difícil, entonces puede considerar adoptar un buen patrón de diseño: Flux .
Es simplemente una colección de reglas que define cómo almacenar y mutar el estado general de la aplicación, y usar ese estado para representar componentes.
Hay muchas implementaciones Flux, y la aplicación oficial de Facebook es una de ellas. Aunque se considera el que contiene más código repetitivo, es más fácil de entender ya que la mayoría de las cosas son explícitas.
Algunas de las otras alternativas son flummox fluxxor fluxible y redux .
fuente
Una vez estuve donde estás ahora, como principiante a veces te sientes fuera de lugar sobre cómo reaccionar para hacer esto. Voy a tratar de abordarlo de la misma manera que lo pienso ahora.
Los Estados son la piedra angular de la comunicación.
Por lo general, se trata de la forma en que altera los estados en este componente en su caso, señala tres componentes.
<List />
: Que probablemente mostrará una lista de elementos según un filtro<Filters />
: opciones de filtro que alterarán sus datos.<TopBar />
: Lista de opciones.Para orquestar toda esta interacción, necesitará un componente superior, llamémoslo Aplicación, que transmitirá acciones y datos a cada uno de estos componentes para que, por ejemplo, pueda verse así
Entonces, cuando
setFilter
se llama, afectará el elemento filtrado y volverá a representar ambos componentes ;. En caso de que esto no esté completamente claro, le hice un ejemplo con la casilla de verificación que puede verificar en un solo archivo:fuente
El siguiente código me ayuda a configurar la comunicación entre dos hermanos. La configuración se realiza en su padre durante las llamadas render () y componentDidMount (). Se basa en https://reactjs.org/docs/refs-and-the-dom.html Espero que ayude.
fuente
Curiosamente nadie mencionó
mobx
. La idea es similar aredux
. Si tengo una pieza de datos a la que están suscritos múltiples componentes, entonces puedo usar esta información para manejar múltiples componentes.fuente