想象一下像Quora。
[
{
type: "question",
answers: [
{
type: "answer",
upvotes: [
{
type: "upvote"
}
/* more upvotes */
],
comments [
{
type: "comment"
}
/* more comments */
]
}
/* more answers */
]
}
/* more questions */
]
我确实有类似QuestionsStore
的东西。但对于所有儿童实体,我不确定如何处理它们。来自Backbone的我认为每个答案应该有一个UpvotesStore
和一个CommentsStore
,组件会从这些商店获取数据并订阅他们的更新。据我了解Flux," child" /关系商店有点不常见。
当每个组件订阅来自QuestionsStore
的更新时,会导致类似以下内容:
/* in CommentsComponent */
onUpdate: function() {
this.setState({
comments: QuestionsStore.getComments({questionId: 1, answerId: 1});
});
}
或更极端:
/* in CommentComponent */
onUpdate: function() {
this.setState(QuestionsStore.getComment({questionId: 1, answerId: 1, commentId: 1}));
}
由于关系数据存在于树结构中,因此每个组件都需要知道所有" parent" id为了能够从QuestionsStore
查询他们的数据。我发现这有些奇怪。
那么处理关系(一对多)数据结构的最佳Flux模式是什么?
答案 0 :(得分:2)
我看到的两个主要选项是保留嵌套结构,或者将其解析为平面结构,其中每个对象根据其关系包含对其他对象的引用。我认为最好的方法取决于如何访问数据。
如果嵌套结构始终镜像视图层次结构,则保持嵌套结构相对容易。例如,考虑:
// render a <Question/>
render: function() {
var question = this.props.data,
answers = question.answers.map(function(answer, i) {
return <Answer key={i} data={answer}/>
});
return (
<div className="question">
{answers}
</div>
);
}
// render an <Answer/>
render: function() {
var answer = this.props.data,
comments = answer.comments.map(function(comment, i) {
return <Comment key={i} data={comment}/>
});
return (
<div className="answer">
...
{comments}
</div>
);
}
// and so on
让顶级组件从商店获取数据并通过这样的道具传递它比使每个组件跟踪索引以在商店中查找嵌套数据更容易管理。
这种方法的潜在缺点是嵌套数据更难以从其上下文之外访问。例如,如果您想跟踪给定用户的所有评论,您的用户数据仍然必须求助于索引来跟踪哪些问题,每个问题的答案索引,以及每个答案的哪些评论索引指向正确的评论。在这种情况下,您可能会受益于平面数据结构。
扁平结构需要更多的工作来设置,但具有可以立即访问每个对象的优点。假设您的数据作为嵌套对象进入,则需要通过遍历树来查找所有节点,为每个节点分配一个唯一键,使用对相应键的引用替换其子树,然后将所有结果存储在适当的商店。但正如丹阿布拉莫夫指出的那样,有人已经提供module来促进这一点。
现在你的问题可以参考答案,每个答案都可以引用评论,重新创建原始的嵌套结构是微不足道的;但您的用户也可以参考评论,而无需跟踪他们与答案或问题的关联。
这基本上是Git如何在内部运作;它对于包含大量冗余的数据树特别有效(例如,包含未更改文件的多个提交都可以指向同一个对象)。