Я создаю простое приложение CRUD с помощью Flux Dispatcher от Facebook, чтобы обрабатывать создание и редактирование сообщений для английского учебного сайта. В настоящее время я имею дело с API, который выглядит следующим образом:Как обрабатывать вложенные вызовы 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)
});
}
}
Основная проблема заключается в том, что диспетчер потока бросает «не может отправить в середине отправки» инвариантной ошибка при SentencesActions.fetch
называется в _handlePostsStoreChange
обратного вызова becau se, что метод SentencesActions запускает отправку до завершения обратного вызова отправки для предыдущего действия.
Я знаю, что могу исправить это, используя что-то вроде _.defer
или setTimeout
. Однако мне кажется, что я просто исправляю проблему здесь. Кроме того, я считал, что я делаю всю эту выборку логики в самих действиях, но это тоже не правильно, и затруднит обработку ошибок. У меня есть все мои сущности, разделенные на свои собственные магазины и действия - не должно ли быть какой-то способ на уровне компонента составлять то, что мне нужно от соответствующих магазинов каждого объекта?
Открыт для любого совета любого, кто совершил нечто подобное!
Вы пытались использовать 'waitFor'? https://facebook.github.io/flux/docs/dispatcher.html – knowbody
@knowbody Да, я попытался использовать 'waitFor', но на самом деле это не похоже на проблему, поскольку проблема в том, что второе действие отправляется до первого завершения. Однако, может быть, мое понимание «waitFor» ошибочно, и я просто не использую его правильно? – joeellis
@joeellis: возможно ли, чтобы вы собрали демо-версию jsFiddle, пожалуйста, продемонстрировав свою проблемную ситуацию? –