问题
I have Posts
and Comments
and I'm trying to build the UI for adding a comment to a post using React and Meteor. When I submit a comment, the new comment appears and then immediately disappears. When I refresh the page, the new comment is there.
Meteor.publish('post', function(postId) {
return Posts.find(postId);
});
Meteor.publish('comments.forPost', function(postId) {
const post = Posts.findOne(postId);
return Comments.find({_id: { $in : post.comments } } );
});
Meteor.methods({
'comments.insert'({ postId, content }) {
check(postId, String);
check(content, String);
const commentId = Comments.insert({
createdAt: new Date(),
userId: this.userId,
content,
});
Posts.update(postId, { $addToSet: { comments: commentId }});
});
In my React component I use createContainer
:
export default createContainer((props) => {
const id = props.params.id;
const postHandle = Meteor.subscribe('post', id);
const isLoading = !postHandle.ready();
Meteor.subscribe('comments.forPost', id);
const post = Posts.findOne(id);
const comments =
isLoading ? [] : Comments.find({_id: { $in: post.comments } }).fetch();
console.log(comments.length);
return {
comments,
isLoading,
question,
};
}, PostShow);
My console.log
statement prints the new length after adding a comment, and then prints the previous number.
回答1:
That is because in your publication post
is evaluated only once and therefore your cursor is not "reactive" in the sense that it will not re-evaluate the query when you comments
change, as it is fetched.
There are several ways to do this, either directly, using a package or redesign to avoid it.
- Do it directly, as demonstrated in this video. I would not recommend this unless you really know what you are doing and have a very good reason to do so. It involves directly observing your first query and manually pushing updates to the client when something changes. I think that David Weldon summarizes it quite well in this answer.
- De-normalize the data, which will require you to keep track of the duplicates as the canonical data source changes. This moves the complexity to another area of the code, and is not very easy to implement. There are certain design patterns, such as CQRS, that allow you to achieve this in a fairly robust and performant way, but they are not easy to grasp and implement.
- Use a package, such as reywood:publish-composite, that makes it a little less painful that the manual option at the price of potential performance penalty.
- Change your data structure to allow easy publication. That depends on your use-case and the rest of the requirements. In your case, having an
articleId
in each comment document will make publishing all of the comments for each article trivial. You may want to add an index to that field to boost performance.
BTW, the "reactive join" problem is still unsolved and will likely remain so since a new GrapnQL-based data model is coming to Meteor via Apollo soon.
来源:https://stackoverflow.com/questions/37632033/meteor-adding-an-associated-record-doesnt-work