顺路发现于 #3209 (那个 PR 只补了 feed 取数的 loading 信号源,没有动 feedItems 的生命周期)。
现象
packages/app-shell/src/views/RecordDetailView.tsx:
const [feedItems, setFeedItems] = useState< FeedItem[] >([])(约 L299);
取数 effect 的依赖里有 pureRecordId,换记录时会重新跑两个 find;
但两处回填都是 按 id 归并到 prev :setFeedItems(prev => { const byId = new Map(...); for (const item of [...prev, ...mapped]) ... });
全文件没有任何一处把 feedItems 重置回 [] (setFeedItems 只出现在归并与乐观更新里)。
RecordDetailView 在路由下是不会重挂载 的(console/AppContent.tsx 里 < RecordDetailView dataSource=... objects=... onEdit=... /> 没有 key;ObjectView / ObjectDataPage / InterfaceListPage 的抽屉用法同理,只换 recordIdOverride),所以在同一个对象里从记录 A 点到记录 B,A 的评论和活动行会继续留在 B 的讨论面板上 ,B 自己的行归并进来排在一起。id 不同 → Map 去重不掉。
复现证据
在 #3209 的测试装置上跑过一次(临时用例,未提交):
render(< RecordDetailView … recordIdOverride="rec-A" />)
→ 屏幕上出现 "comment for crm_account:rec-A"
rerender(< RecordDetailView … recordIdOverride="rec-B" />)
→ 屏幕上出现 "comment for crm_account:rec-B"
→ 断言 screen.queryByText("comment for crm_account:rec-A") 仍然为真 —— 通过
也就是说 A 的评论确实还在 B 的页面上。
影响
用户在列表里连续点几条记录,讨论面板会越滚越长,混着别的记录的评论 —— 是串数据 ,不只是视觉问题;
顺带压掉 chatter 那条链没有 loading 信号源:RecordDetailView / record:chatter 从不给 RecordChatterPanel 传 loading #3209 的 loading 态:换记录时 feedLoading 会正确转 true,但 RecordActivityTimeline 的 loading 分支条件是 loading && filtered.length === 0(RecordActivityTimeline 收下 loading 却完全不读——取数中的 feed 显示的是"暂无活动" #3205 有意为之:不要让刷新把已在屏上的 feed 变成 spinner),此时 filtered 里还有上一条记录的残留行,于是渲染的是上一条记录的内容 而不是加载态。所以这条不修,chatter 那条链没有 loading 信号源:RecordDetailView / record:chatter 从不给 RecordChatterPanel 传 loading #3209 在「记录间导航」这个路径上仍然看不到加载态。
建议方向(未拍板)
取数 effect 里换记录时把 feedItems 清空是最直接的,但要和乐观更新(handleAddComment / handleAddReply / handleToggleReaction 往 feedItems 里塞的本地行)对齐,别把用户刚发出、还没落库的评论清掉。可能的做法是把 feed 状态按 objectName:recordId 键存(和 #3209 的 feedFetchKey 同一把钥匙),读的时候只取当前键那一份 —— 这样「清空」就是自然结果而不是一次额外的 setState 竞态。请维护者定方向,#3209 的 PR 里没有顺手改。
参考
顺路发现于 #3209(那个 PR 只补了 feed 取数的 loading 信号源,没有动
feedItems的生命周期)。现象
packages/app-shell/src/views/RecordDetailView.tsx:const [feedItems, setFeedItems] = useState< FeedItem[] >([])(约 L299);pureRecordId,换记录时会重新跑两个find;setFeedItems(prev => { const byId = new Map(...); for (const item of [...prev, ...mapped]) ... });feedItems重置回[](setFeedItems只出现在归并与乐观更新里)。RecordDetailView在路由下是不会重挂载的(console/AppContent.tsx里< RecordDetailView dataSource=... objects=... onEdit=... />没有key;ObjectView/ObjectDataPage/InterfaceListPage的抽屉用法同理,只换recordIdOverride),所以在同一个对象里从记录 A 点到记录 B,A 的评论和活动行会继续留在 B 的讨论面板上,B 自己的行归并进来排在一起。id 不同 → Map 去重不掉。复现证据
在 #3209 的测试装置上跑过一次(临时用例,未提交):
也就是说 A 的评论确实还在 B 的页面上。
影响
record:chatter从不给RecordChatterPanel传loading#3209 的 loading 态:换记录时feedLoading会正确转 true,但RecordActivityTimeline的 loading 分支条件是loading && filtered.length === 0(RecordActivityTimeline收下loading却完全不读——取数中的 feed 显示的是"暂无活动" #3205 有意为之:不要让刷新把已在屏上的 feed 变成 spinner),此时filtered里还有上一条记录的残留行,于是渲染的是上一条记录的内容而不是加载态。所以这条不修,chatter 那条链没有 loading 信号源:RecordDetailView /record:chatter从不给RecordChatterPanel传loading#3209 在「记录间导航」这个路径上仍然看不到加载态。建议方向(未拍板)
取数 effect 里换记录时把
feedItems清空是最直接的,但要和乐观更新(handleAddComment/handleAddReply/handleToggleReaction往feedItems里塞的本地行)对齐,别把用户刚发出、还没落库的评论清掉。可能的做法是把 feed 状态按objectName:recordId键存(和 #3209 的feedFetchKey同一把钥匙),读的时候只取当前键那一份 —— 这样「清空」就是自然结果而不是一次额外的 setState 竞态。请维护者定方向,#3209 的 PR 里没有顺手改。参考
packages/app-shell/src/views/RecordDetailView.tsx(feedItems的 state、两处setFeedItems(prev => …)归并、取数 effect 的依赖)packages/plugin-detail/src/RecordActivityTimeline.tsx(loading && filtered.length === 0分支)record:chatter从不给RecordChatterPanel传loading#3209 /RecordActivityTimeline收下loading却完全不读——取数中的 feed 显示的是"暂无活动" #3205 /record:activity的 feed 结构上不可能有内容——11 个声明的输入全是空 feed 上的过滤器(objectstack#4413 的形状,第三次) #3165