Я создаю простое приложение CRUD с помощью Facebook Flux Dispatcher, чтобы обрабатывать создание и редактирование сообщений для английского учебного сайта. В настоящее время я занимаюсь api, который выглядит так:
/posts/:post_id
/posts/:post_id/sentences
/sentences/:sentence_id/words
/sentences/:sentence_id/grammars
На страницах показа и редактирования для приложения я хотел бы показать всю информацию для данного сообщения, а также все его предложения и слова предложений и данные грамматики на одной странице.
Проблема, с которой я сталкиваюсь, - это выяснить, как инициировать все асинхронные вызовы, необходимые для сбора всех этих данных, а затем составлять нужные мне данные из всех хранилищ в один объект, который я могу установить как состояние в моем компонент верхнего уровня. Текущий (ужасный) пример того, что я пытался сделать, это следующее:
Верхний уровень PostsShowView:
class PostsShow extends React.Component {
componentWillMount() {
// this id is populated by react-router when the app hits the /posts/:id route
PostsActions.get({id: this.props.params.id});
PostsStore.addChangeListener(this._handlePostsStoreChange);
SentencesStore.addChangeListener(this._handleSentencesStoreChange);
GrammarsStore.addChangeListener(this._handleGrammarsStoreChange);
WordsStore.addChangeListener(this._handleWordsStoreChange);
}
componentWillUnmount() {
PostsStore.removeChangeListener(this._handlePostsStoreChange);
SentencesStore.removeChangeListener(this._handleSentencesStoreChange);
GrammarsStore.removeChangeListener(this._handleGrammarsStoreChange);
WordsStore.removeChangeListener(this._handleWordsStoreChange);
}
_handlePostsStoreChange() {
let posts = PostsStore.getState().posts;
let post = posts[this.props.params.id];
this.setState({post: post});
SentencesActions.fetch({postId: post.id});
}
_handleSentencesStoreChange() {
let sentences = SentencesStore.getState().sentences;
this.setState(function(state, sentences) {
state.post.sentences = sentences;
});
sentences.forEach((sentence) => {
GrammarsActions.fetch({sentenceId: sentence.id})
WordsActions.fetch({sentenceId: sentence.id})
})
}
_handleGrammarsStoreChange() {
let grammars = GrammarsStore.getState().grammars;
this.setState(function(state, grammars) {
state.post.grammars = grammars;
});
}
_handleWordsStoreChange() {
let words = WordsStore.getState().words;
this.setState(function(state, words) {
state.post.words = words;
});
}
}
И вот мои PostsActions.js - другие сущности (предложения, грамматики, слова) также имеют похожие ActionCreators, которые работают аналогичным образом:
let api = require('api');
class PostsActions {
get(params = {}) {
this._dispatcher.dispatch({
actionType: AdminAppConstants.FETCHING_POST
});
api.posts.fetch(params, (err, res) => {
let payload, post;
if (err) {
payload = {
actionType: AdminAppConstants.FETCH_POST_FAILURE
}
}
else {
post = res.body;
payload = {
actionType: AdminAppConstants.FETCH_POST_SUCCESS,
post: post
}
}
this._dispatcher.dispatch(payload)
});
}
}
Основная проблема заключается в том, что диспетчер Flux генерирует инвариантную ошибку "Невозможно отправить в середине отправки", когда SentencesActions.fetch
вызывается в обратном вызове _handlePostsStoreChange
, потому что этот метод SentencesActions запускает отправку перед обратным вызовом отправки для предыдущее действие завершено.
Я знаю, что могу исправить это, используя что-то вроде _.defer
или setTimeout
. Однако мне кажется, что я просто исправляю проблему здесь. Кроме того, я считал, что я делаю всю эту выборку логики в самих действиях, но это тоже не правильно, и затруднит обработку ошибок. У меня есть каждый из моих объектов, разделенных на свои собственные магазины и действия - не должно ли быть какой-то способ на уровне компонента составлять то, что мне нужно от каждой сущности, соответствующих хранилищам?
Откройте любой совет от любого, кто совершил нечто подобное!