Relay Subscriptions 正确使用方式?如何避免评论重复问题
解决评论重复加载的问题
看起来你遇到了经典的“初始数据拉取+全量订阅推送”导致的重复问题——页面加载时CommentsContainer先拿了一遍评论,订阅又把所有评论再推一次,自然每条都重复了。咱们可以通过在订阅回调里做存在性检查,只添加新的评论edge来解决这个问题。
核心思路
不管你是用本地state管理评论,还是用Apollo这类状态库,关键步骤都是:
- 拿到现有评论的edges列表
- 用评论的唯一标识(比如
id)判断新推送的记录是否已存在 - 只把不存在的记录添加到现有列表中
示例代码
情况1:用本地State管理评论
假设你的订阅回调是更新组件state,那可以这样修改:
// 定义订阅回调,处理推送过来的评论数据 const handleNewComments = (newCommentEdges) => { this.setState(prevState => { // 拿到现有评论的edges const existingEdges = prevState.comments.edges; // 过滤掉已经存在的评论(用node.id作为唯一判断) const uniqueNewEdges = newCommentEdges.filter(newEdge => { return !existingEdges.some(edge => edge.node.id === newEdge.node.id); }); // 合并现有edges和新的唯一edges return { comments: { ...prevState.comments, edges: [...existingEdges, ...uniqueNewEdges] } }; }); }; // 你的订阅函数 const commentSubscription = () => { // 假设这里是订阅的初始化逻辑,比如用WebSocket或者GraphQL订阅 const subscription = someSubscriptionClient.subscribe({ query: YOUR_COMMENT_SUBSCRIPTION_QUERY }, handleNewComments); };
情况2:用Apollo Client管理缓存
如果是用Apollo做数据管理,那可以在subscribeToMore的updateQuery里做去重:
const commentSubscription = () => { // 假设这是你的组件实例,调用subscribeToMore this.props.subscribeToMore({ document: COMMENT_SUBSCRIPTION_QUERY, updateQuery: (prev, { subscriptionData }) => { if (!subscriptionData.data) return prev; const newCommentEdge = subscriptionData.data.commentAdded; // 假设订阅返回单条新评论edge const existingEdges = prev.comments.edges; // 检查这条评论是否已经存在 const commentExists = existingEdges.some(edge => edge.node.id === newCommentEdge.node.id); if (commentExists) { // 已存在,直接返回原有数据,不更新 return prev; } // 不存在,添加到edges列表 return { ...prev, comments: { ...prev.comments, edges: [...existingEdges, newCommentEdge] } }; } }); };
额外建议
如果能修改服务器端的订阅逻辑,最好让订阅只推送新增的评论,而不是全量评论——这样从源头上避免重复,前端也不用做额外处理。但如果服务器端改不了,前端的去重逻辑就是最稳妥的方案。
内容的提问来源于stack exchange,提问作者Martin Dawson
相关产品推荐
相关产品推荐

