javascript - Gerir a dependência de dados da store em React/Flux
Tenho uma aplicação web desenvolvida usando a Arquitetura Flux do Facebook. A página tem duas vistas: uma exibe uma lista de itens TODO. A segunda vista exibe um conjunto aleatório de itens TODO.
Existem claramente duas preocupações que precisam ser geridas pelas lojas. A primeira é a lista de TODO's disponíveis. A segunda é a lista de itens TODO selecionados aleatoriamente.
Tenho assim um TODOStore, cuja preocupação é unicamente gerir os itens TODO disponíveis. Tem ações para loadTODOs, addTODO, deleteTODO, editTODO. No arranque, este store não carrega todos os itens TODO. Quero que ele recupere a lista de itens TODO da base de dados apenas quando necessário.
A segunda loja é a RandomTODOListStore. A sua responsabilidade é gerir os itens TODO selecionados aleatoriamente. Parece-me que a RandomTODOListStore deveria aceder aos itens TODO através da 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");
}
}
O problema com isto é que, como mencionado anteriormente, o TODOStore não carrega os itens TODO na inicialização.
A questão é: "Como é que o RandomTODOListStore garante que o TODOStore já recuperou os itens TODO?".
Resposta #1
A implementação do Flux proposta utiliza um método waitFor para sincronizar os stores. Eu criei o Reflux para lidar com isto de forma muito mais fácil, permitindo que os stores possam ouvir outros stores. O efeito dessa funcionalidade é que garantirá que o store anterior na cadeia tenha tratado os seus dados.
A interface é um pouco diferente, porque o Reflux não depende de constantes de string para discernir ações, por isso aqui está um exemplo.
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 isto faça sentido.
Resposta #2
Acho que é por isso que a arquitectura Flux menciona a necessidade de sincronizar os stores com o método waitFor mencionado aqui
Se quiser sincronizar as suas lojas, a sua RandomTODOListStore provavelmente deverá parecer com:
case Constants.LOAD_RANDOM_TODO:
Dispatcher.waitFor([TodoStore.dispatcherIndex],this.loadRandomTODO);
break;
Então, no seu TodoStore, você pode reagir a Constants.LOAD_RANDOM_TODO e carregar a lista de tarefas se ainda não estiverem carregadas.
No entanto, penso que isto é excessivamente complicado, e provavelmente não deves criar outra store para tarefas aleatórias, uma vez que esta store irá (acho eu) sempre delegar na verdadeiro store de tarefas. Simplesmente usa TodoStore.getRandom() em vez disso
Editar:
Sim, a TodoStore não precisa de saber como é usada. Assim, quando quiser obter uma tarefa aleatória, pode provavelmente usar o mesmo evento que utiliza, como Constants.LOAD_TODOS e depois obter uma tarefa aleatória dessa store com TodoStore.getTodos()[randomIndex]
Se ambos os componentes dispararem o evento simultaneamente, pode ignorar o segundo evento
Outra solução é fazer com que o RandomTODOListStore reaja ao evento carregado e selecione alguns todos da loja principal para colocá-los no RandomTODOListStore:
case Constants.TODOS_LOADED:
this.randomTodos = randomSubset(TodoStore.getTodos,subsetSize);
break;
Podes inspirar-te no exemplo Async do Fluxxor: para dados assíncronos, não há apenas um evento disparado, mas 2 (comando + sucesso/erro)
