我正在使用 Facebook 的 Flux Dispatcher 创建一个简单的 CRUD 应用程序来处理英语学习网站的帖子的创建和编辑。我目前正在处理一个如下所示的 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
- 但是我真的觉得我只是在这里修补这个问题。此外,我考虑在操作本身中执行所有这些获取逻辑,但这似乎也不正确,并且会使错误处理更加困难。我将我的每个实体分离到他们自己的存储和操作中 - 组件级别不应该有某种方法来组合我需要从每个实体各自的存储中获取的内容吗?
接受任何已经完成类似事情的人的任何建议!