javascript - Gestión de la dependencia de datos de la tienda en React/Flux
Tengo una aplicación web desarrollada utilizando la Arquitectura Flux de Facebook. La página tiene dos vistas: una muestra una lista de elementos TODO. La segunda vista muestra un conjunto aleatorio de elementos TODO.
Hay claramente dos preocupaciones que deben ser gestionadas por las tiendas. La primera es la lista de TODO disponibles. La segunda es la lista de elementos TODO seleccionados al azar.
Así que tengo un TODOStore, cuya preocupación es únicamente gestionar los elementos TODO disponibles. Tiene acciones para loadTODOs, addTODO, deleteTODO, editTODO. Al iniciar, esta tienda no carga todos los elementos TODO. Quiero que recupere la lista de elementos TODO de la base de datos solo cuando sea necesario.
La segunda tienda es la RandomTODOListStore. Su responsabilidad es gestionar los elementos TODO seleccionados al azar. Me parece que la RandomTODOListStore debería acceder a los elementos TODO a través de la TODOStore, usando TODOStore.getTODOItems().
function RandomTODOListStore() {
var $randomTODOs = [];
dispatcher.register(function(payload) {
var action = payload.action;
switch (action.actionType) {
case Constants.LOAD_RANDOM_TODO:
loadRandomTODO();
break;
}
});
function loadRandomTODO() {
$randomTODOs = selectRandom(TODOStore.getTODOList());
emit("change");
}
}
El problema con esto es que, como se mencionó anteriormente, el TODOStore no carga los elementos TODO al iniciar.
La pregunta es: "¿Cómo garantiza el RandomTODOListStore que el TODOStore ya ha recuperado los elementos TODO?".
Respuesta #1
La implementación propuesta de Flux utiliza un método waitFor para sincronizar los stores. Creé Reflux para manejar esto de manera mucho más fácil, permitiendo que los stores puedan escuchar a otros stores. El efecto de esa característica es que garantizará que el store anterior en la cadena haya manejado sus datos.
La interfaz es un poco diferente, porque Reflux no depende de constantes de cadena para discernir acciones, así que aquí hay un ejemplo.
var TodoActions = Reflux.createActions(['load']);
var todoStore = Reflux.createStore({
init: function() {
// Listen to the load action
this.listenTo(TodoActions.load, this.loadActions);
},
loadActions: functions() {
var loadedActions = [];
// load your actions into loadedActions
// and do then the following inside the ajax
// callback when it is done:
this.trigger(loadedActions);
}
});
var randomTodoStore = Reflux.createStore({
init: function() {
// You may listen to stores as well
this.listenTo(todoStore, onLoadedActions);
},
onLoadedActions: function(loadedActions) {
// loaded actions will be passed in from the
// dotoStores change event trigger
// you may do your select random from loaded
// actions list
}
});
// Invoke the action
TodoActions.load();
Espero que esto tenga sentido.
Respuesta #2
Creo que por eso la arquitectura Flux menciona la necesidad de sincronizar las tiendas con el método waitFor mencionado aquí
Si quieres sincronizar tus tiendas, tu RandomTODOListStore probablemente debería verse así:
case Constants.LOAD_RANDOM_TODO:
Dispatcher.waitFor([TodoStore.dispatcherIndex],this.loadRandomTODO);
break;
Luego, en tu TodoStore, puedes reaccionar a Constants.LOAD_RANDOM_TODO y cargar la lista de tareas si aún no se han cargado.
Sin embargo, creo que esto está demasiado complicado, y probablemente no deberías crear otra tienda para tareas aleatorias, ya que esta tienda (supongo) siempre delegará en la tienda real de tareas. Simplemente usa TodoStore.getRandom() en su lugar
Editar:
Sí, TodoStore no necesita saber cómo se utiliza. Por lo tanto, cuando quieras obtener un todo aleatorio, probablemente puedas usar el mismo evento que usas, como Constants.LOAD_TODOS y luego obtener un todo aleatorio de esa tienda con TodoStore.getTodos()[randomIndex]
Si ambos componentes activan el evento simultáneamente, puedes ignorar el segundo evento
Otra solución es hacer que el RandomTODOListStore reaccione al evento cargado y seleccione algunas tareas del almacén principal para ponerlas en el RandomTODOListStore:
case Constants.TODOS_LOADED:
this.randomTodos = randomSubset(TodoStore.getTodos,subsetSize);
break;
Puedes inspirarte en el ejemplo Async de Fluxxor: para datos asíncronos, no se dispara un solo evento sino 2 (comando + éxito/fallo)
