修复"查找聊天记录"跳转定位到原消息在全部入口100%失效
componentDidUpdate里的jumpToSeq检查只在这个值发生变化时触发,但
tinode-web.jsx从不会同时渲染MessagesView和第7章侧边栏(!chapterSevenActive
门禁),所以从History的搜索结果/图片宫格/视频宫格跳转,每次都是卸载
第7章视图、挂载一个"首次渲染就已经带着jumpToSeq"的全新MessagesView
实例——componentDidUpdate根本不会跑(它不处理首次挂载)。7.12/7.15/
7.16全部"定位到消息来源"入口100%失效:jumpseq参数永久留在URL里,
会话固定停在最底部。
修复过程中还发现一个真实的竞态:首次挂载意味着componentSetup()刚刚
才发起topic订阅(异步、fire-and-forget),jumpToMessage自己的
topic.getMeta()调用要求订阅已建立,立即调用会抢在订阅完成前——实测
这个抢跑的getMeta()调用真实收到了服务端 {"code":403,"text":"permission
denied"} 拒绝(不是本地兜底,是真实的服务端往返),而真正的订阅请求
当时还在路上。改为轮询已有的isSubscribed()标志(而不是猜一个固定延迟
或改造subscribe()暴露其内部promise),封顶5秒,真正卡住的订阅仍会
落到jumpToMessage自己已有的错误处理上。
第十二轮最小粒度测试 Ch7 发现,已用真实浏览器验证:从工作台等其它
页面跳转过来时,消息正确加载、jumpseq参数正确从URL清除。
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
6882103461
commit
68044fa1bb
@@ -288,6 +288,45 @@ class MessagesView extends React.Component {
|
||||
|
||||
this.componentSetup({}, {});
|
||||
|
||||
// Ch.7: jump to a message found via chat-history search/media grid (content-library-view.jsx's
|
||||
// History) -- the componentDidUpdate check a few lines below only fires on a *change* to
|
||||
// jumpToSeq while this component stays mounted, but tinode-web.jsx never renders MessagesView
|
||||
// and a Ch.7 side panel at the same time (`!chapterSevenActive` gates it) -- every jump from
|
||||
// History's search results/image grid/video grid therefore unmounts the Ch.7 view and mounts a
|
||||
// *brand new* MessagesView instance with jumpToSeq already set on its very first render, which
|
||||
// componentDidUpdate never sees (it doesn't run for the initial mount). Confirmed live: the
|
||||
// seq stayed in the URL indefinitely (jumpToMessage's own `removeUrlParam` call never fired)
|
||||
// and the conversation opened at the bottom instead of scrolling to the found message --
|
||||
// 100% reproducible for every Ch.7 "定位到消息来源" entry point, not an intermittent timing issue.
|
||||
if (this.props.jumpToSeq) {
|
||||
const seq = parseInt(this.props.jumpToSeq, 10);
|
||||
const topicObj = this.props.tinode && this.props.topic ? this.props.tinode.getTopic(this.props.topic) : null;
|
||||
const attemptJump = () => this.jumpToMessage(seq);
|
||||
// A first-ever mount also means `componentSetup()` just above only *started* subscribing
|
||||
// this topic (subscribe() -> topic.subscribe() is async, fire-and-forget from here) --
|
||||
// jumpToMessage's own topic.getMeta() call requires an already-established subscription,
|
||||
// and firing immediately races ahead of it: confirmed live, this raced getMeta() call came
|
||||
// back as a real `{"code":403,"text":"permission denied"}` control message (not a local
|
||||
// guard, an actual rejected server round trip) while the real subscribe's own request was
|
||||
// still in flight one id apart. Poll the already-exposed isSubscribed() flag rather than
|
||||
// guessing a fixed delay or reworking subscribe()'s fire-and-forget call sites to expose
|
||||
// their promise; capped at 5s so a genuinely stuck subscribe still falls through to
|
||||
// jumpToMessage's own existing error handling instead of waiting forever.
|
||||
if (topicObj && !topicObj.isSubscribed()) {
|
||||
let tries = 0;
|
||||
const waitForSubscription = () => {
|
||||
if (topicObj.isSubscribed() || ++tries > 25) {
|
||||
attemptJump();
|
||||
} else {
|
||||
window.setTimeout(waitForSubscription, 200);
|
||||
}
|
||||
};
|
||||
waitForSubscription();
|
||||
} else {
|
||||
attemptJump();
|
||||
}
|
||||
}
|
||||
|
||||
getBootstrap().then(data => {
|
||||
this.setState({messagePolicy: data.message_policy || null});
|
||||
}).catch(_ => {});
|
||||
|
||||
Reference in New Issue
Block a user