【发布时间】:2020-07-06 16:11:31
【问题描述】:
我有一个讨论对象列表,其中包含一个 cmets 数组,每个评论都可以包含一个回复数组。我以这种方式显示讨论:
<div v-for="comment in comments" v-bind:key="comment._id">
<Comment :itemId="itemId" :comment="comment" />
<Replies v-if="comment.replies.length > 0" :itemId="itemId" :comment="comment" />
</div>
<Button value="Load more" @clicked="loadMoreComments(itemId)" />
和回复:
<div v-for="reply in replies" v-bind:key="reply._id">
<Comment :itemId="itemId" :comment="reply" />
</div>
<Button :value="Load more" @clicked="loadChild()"/>
如您所见,两者都使用相同的模式。它们在计算属性上有所不同:
computed: {
comments() {
return this.$store.getters.DISCUSSION.comments.map(id => this.$store.getters.GET_COMMENT(id));
},
replies() {
return this.$store.getters.GET_REPLIES(this.comment).map(id => this.$store.getters.GET_COMMENT(id));
},
},
当我点击 cmets 的加载更多按钮时,会出现新的 cmets。但是当我在回复中点击加载更多按钮时,虽然我可以在调试器中看到数组被放大,但没有显示新的回复。
Vuex 存储子模块:
state: () => ({
discussion: {
incomplete: true,
comments: [],
},
comments: {},
}),
getters: {
DISCUSSION: state => state.discussion,
GET_COMMENT: state => id => state.comments[id],
GET_REPLIES: state => (comment) => {
if (comment.allShown) {
return comment.replies;
}
return comment.replies.slice(0, REPLY_LIMIT);
},
},
mutations: {
APPEND_COMMENTS: (state, payload) => {
const { comments, incomplete, userId } = payload;
state.discussion.incomplete = incomplete;
const commentIds = [];
comments.forEach(comment => processComment(state, comment, commentIds, userId));
state.discussion.comments = state.discussion.comments.concat(commentIds);
},
PREPEND_COMMENTS: (state, payload) => {
const { comments, userId } = payload;
const commentIds = [];
comments.forEach(comment => processComment(state, comment, commentIds, userId));
state.discussion.comments = commentIds.concat(state.discussion.comments);
},
SET_REPLIES: (state, payload) => {
console.log('SET_REPLIES');
const { commentId, replies, userId, replace } = payload;
const comment = state.comments[commentId];
if (!comment) {
return;
}
state.comments[commentId].showAll = true;
const commentIds = [];
replies.forEach(reply => processComment(state, reply, commentIds, userId));
if (!comment.replies || comment.replies.length === 0 || replace) {
state.comments[commentId].replies = commentIds;
} else {
state.comments[commentId].replies = comment.replies.concat(commentIds);
}
},
}
function processComment(state, comment, commentIds, userId) {
if (comment.replies) {
const repliesIds = [];
comment.replies.forEach((reply) => {
reply.voted = hasVoted(reply.votes, userId);
state.comments[reply._id] = reply;
repliesIds.push(reply._id);
});
comment.replies = repliesIds;
comment.allShown = comment.replies.length < REPLY_LIMIT;
} else if (!comment.parentId) {
comment.replies = [];
comment.allShown = false;
}
state.comments[comment._id] = comment;
commentIds.push(comment._id);
}
完整的源代码在那里:https://github.com/literakl/mezinamiridici/tree/comment_refactoring/spa
这里是最小可重现代码框:https://codesandbox.io/s/frosty-taussig-v8u4b?file=/src/module.js
我已经证实这是因为带有参数的 getter。当我将回复放入静态数组以便我可以使用无参数 getter 时,它开始工作。
我遵循这个建议:https://forum.vuejs.org/t/vuex-best-practices-for-complex-objects/10143
问题出在哪里?
更新:
有一点味道是突变GET_REPLIES,因为它适用于传递的对象。所以Vue没有机会检测到对象来自状态。所以我重写了它只传递commentId并从状态加载评论,但它没有帮助。
【问题讨论】:
标签: javascript vue.js vuex