En una aplicación Flux solo debe haber un Despachador. Todos los datos fluyen a través de este concentrador central. Tener un Dispatcher singleton le permite administrar todas las tiendas. Esto se vuelve importante cuando necesita la actualización de la Tienda n. ° 1, y luego hacer que la Tienda n. ° 2 se actualice en sí misma según la Acción y el estado de la Tienda n. ° 1. Flux asume que esta situación es una eventualidad en una aplicación grande. Idealmente, esta situación no debería ocurrir, y los desarrolladores deberían esforzarse por evitar esta complejidad, si es posible. Pero el Singleton Dispatcher está listo para manejarlo cuando llegue el momento.
Las tiendas también son singletons. Deben permanecer tan independientes y desacoplados como sea posible: un universo autónomo que se puede consultar desde una Vista de controlador. El único camino hacia la Tienda es a través de la devolución de llamada que registra con el Despachador. El único camino es a través de las funciones getter. Las tiendas también publican un evento cuando su estado ha cambiado, por lo que Controller-Views puede saber cuándo consultar el nuevo estado, utilizando los captadores.
En su aplicación de ejemplo, habría una sola PostStore
. Esta misma tienda podría administrar las publicaciones en una "página" (pseudo-página) que es más como Newsfeed de FB, donde las publicaciones aparecen de diferentes usuarios. Su dominio lógico es la lista de publicaciones, y puede manejar cualquier lista de publicaciones. Cuando pasamos de pseudopágina a pseudopágina, queremos reinicializar el estado de la tienda para reflejar el nuevo estado. También es posible que deseemos almacenar en caché el estado anterior en localStorage como una optimización para moverse de un lado a otro entre pseudo páginas, pero mi inclinación sería configurar una PageStore
que espere a todas las demás tiendas, gestione la relación con localStorage para todas las tiendas en la pseudo-página, y luego actualiza su propio estado. Tenga en cuenta que esto PageStore
no almacenaría nada sobre las publicaciones, ese es el dominio de laPostStore
. Simplemente sabría si una pseudo-página en particular ha sido almacenada en caché o no, porque las pseudo-páginas son su dominio.
El PostStore
tendría un initialize()
método. Este método siempre borraría el estado anterior, incluso si esta es la primera inicialización, y luego crearía el estado basado en los datos que recibió a través de la Acción, a través del Despachador. Pasar de una pseudopágina a otra probablemente implicaría una PAGE_UPDATE
acción, que desencadenaría la invocación de initialize()
. Hay detalles para resolver la recuperación de datos de la memoria caché local, la recuperación de datos del servidor, la representación optimista y los estados de error XHR, pero esta es la idea general.
Si una pseudopágina en particular no necesita todas las tiendas en la aplicación, no estoy completamente seguro de que haya alguna razón para destruir las que no se utilizan, aparte de las restricciones de memoria. Pero las tiendas no suelen consumir una gran cantidad de memoria. Solo debe asegurarse de eliminar los oyentes de eventos en las Vistas del controlador que está destruyendo. Esto se hace en el componentWillUnmount()
método React .
UserListStore
, con todos los usuarios relevantes en él. Y cada usuario tendría un par de banderas booleanas que describen la relación con el perfil de usuario actual. Algo como{ follower: true, followed: false }
, por ejemplo. Los métodosgetFolloweds()
ygetFollowers()
recuperarían los diferentes conjuntos de usuarios que necesita para la interfaz de usuario.(Nota: he usado la sintaxis ES6 usando la opción JSX Harmony).
Como ejercicio, escribí una aplicación Flux de muestra que permite navegar
Github users
y reposicionar.Se basa en la respuesta de fisherwebdev, pero también refleja un enfoque que uso para normalizar las respuestas API.
Logré documentar algunos enfoques que probé mientras aprendía Flux.
Traté de mantenerlo cerca del mundo real (paginación, sin API de almacenamiento local falsas).
Aquí hay algunos bits en los que estaba especialmente interesado:
switch
con acciones ;Cómo clasifico las tiendas
Traté de evitar parte de la duplicación que he visto en otro ejemplo de Flux, específicamente en las tiendas. Me pareció útil dividir lógicamente las tiendas en tres categorías:
Las tiendas de contenido contienen todas las entidades de la aplicación. Todo lo que tiene una ID necesita su propio Content Store. Los componentes que representan elementos individuales solicitan a los Almacenes de contenido los datos nuevos.
Los almacenes de contenido cosechan sus objetos de todas las acciones del servidor. Por ejemplo,
UserStore
analizaaction.response.entities.users
si existe independientemente de la acción que se active. No hay necesidad de aswitch
. Normalizr facilita aplanar cualquier respuesta API a este formato.Los almacenes de listas realizan un seguimiento de los ID de las entidades que aparecen en alguna lista global (por ejemplo, "feed", "sus notificaciones"). En este proyecto, no tengo tales tiendas, pero pensé en mencionarlas de todos modos. Manejan la paginación.
Normalmente responden a unas pocas acciones (p
REQUEST_FEED
. Ej .REQUEST_FEED_SUCCESS
,REQUEST_FEED_ERROR
).Los almacenes de listas indexadas son como los almacenes de listas, pero definen una relación de uno a muchos. Por ejemplo, "suscriptores del usuario", "observadores de estrellas del repositorio", "repositorios del usuario". También manejan la paginación.
También responden normalmente a unas pocas acciones (por ejemplo
REQUEST_USER_REPOS
,REQUEST_USER_REPOS_SUCCESS
,REQUEST_USER_REPOS_ERROR
).En la mayoría de las aplicaciones sociales, tendrá muchas de estas y desea poder crear rápidamente una más.
Nota: estas no son clases reales o algo así; es justo como me gusta pensar en las tiendas. Aunque hice algunos ayudantes.
StoreUtils
createStore
Este método le brinda la Tienda más básica:
Lo uso para crear todas las tiendas.
isInBag
,mergeIntoBag
Pequeños ayudantes útiles para Content Stores.
PaginatedList
Almacena el estado de paginación y aplica ciertas afirmaciones (no se puede recuperar la página mientras se recupera, etc.).
PaginatedStoreUtils
createListStore
`createIndexedListStore
`createListActionHandler
Hace que la creación de almacenes de listas indexadas sea lo más simple posible al proporcionar métodos repetitivos y manejo de acciones:
createStoreMixin
Un mixin que permite que los componentes sintonicen las tiendas que les interesan, por ejemplo
mixins: [createStoreMixin(UserStore)]
.fuente
Entonces, en Reflux, el concepto de Dispatcher se elimina y solo necesita pensar en términos de flujo de datos a través de acciones y tiendas. Es decir
Cada flecha aquí modela cómo se escucha el flujo de datos, lo que a su vez significa que los datos fluyen en la dirección opuesta. La cifra real para el flujo de datos es la siguiente:
En su caso de uso, si entendí correctamente, necesitamos una
openUserProfile
acción que inicie la carga del perfil del usuario y cambie la página y también algunas acciones de carga de publicaciones que cargarán las publicaciones cuando se abra la página del perfil del usuario y durante el evento de desplazamiento infinito. Así que me imagino que tenemos los siguientes almacenes de datos en la aplicación:En Reflux lo configuraría así:
Las acciones
La tienda de la página
La tienda de perfil de usuario
La tienda de publicaciones
Los componentes
Supongo que tiene un componente para la vista de página completa, la página de perfil de usuario y la lista de publicaciones. Lo siguiente necesita ser conectado:
Action.openUserProfile
con la identificación correcta durante su evento de clic.currentPageStore
que sepa a qué página cambiar.currentUserProfileStore
saber qué datos de perfil de usuario mostrarcurrentPostsStore
para recibir las publicaciones cargadas.Action.loadMorePosts
.Y eso debería ser todo.
fuente