修复未登录状态下深链/跳转到某个话题导致应用整体白屏

handleHashRoute 判断 path[1](话题名)是否合法只检查了 Tinode.topicType(topicName)
这一个语法层面的条件——没登录时把hash设成一个真实群/好友的"#/<topic>"地址(比如
退出登录后浏览器历史回退、或者一个带话题参数的通知/深链在未登录状态下被打开),
话题名本身语法上合法,于是mobilePanel被设成'topic-view'。但render()里
MessagesView真正渲染的前提除了mobilePanel还要求!chapterOneActive(即
this.tinode.isAuthenticated())——这个前提没登录时是假的。结果移动端下
SidepanelView的显示条件(mobilePanel=='sidepanel')和MessagesView的显示条件同时
为假,两边都不渲染,应用整体白屏(app-container是空的,没有任何报错),
仅靠换hash也无法恢复,只能整页刷新。

修复:判断话题合法性时把"当前是否已认证"也纳入,未登录时统一走已经验证过安全的
"话题名非法"分支(topicName置null,mobilePanel回退到sidepanel)。

已实测复现:退出登录后把location.hash设成一个真实群的话题地址,修复前白屏,
修复后正确回退。
This commit is contained in:
Your Name
2026-09-06 15:03:48 +08:00
parent ed9a92896c
commit 4715ea4497
+12 -1
View File
@@ -800,7 +800,18 @@ class TinodeWeb extends React.Component {
// Topic for MessagesView selector.
let topicName = hash.path[1] || null;
if (topicName != this.state.topicSelected) {
if (!Tinode.topicType(topicName)) {
// A syntactically valid topic name is not enough on its own: mobilePanel='topic-view' only
// ever pairs correctly with MessagesView actually being allowed to render, which requires
// !chapterOneActive (i.e. this.tinode.isAuthenticated()) -- see tinode-web.jsx's render().
// Without this check, opening (or being redirected/deep-linked to) a #/<topic> URL while
// logged out set mobilePanel to 'topic-view' anyway; on mobile that made *both* the
// SidepanelView gate (`mobilePanel=='sidepanel'`) and the MessagesView gate
// (`!chapterOneActive`) false at once, so neither rendered -- a permanently blank white
// screen (app-container empty, no thrown error) that a hash change alone couldn't recover
// from, only a full reload. Reproduced live: logging out, then setting location.hash to a
// real group's `#/<topic>` URL. Falling back to the same "invalid topic" branch already used
// for a malformed name reuses a path already proven safe with topicName=null.
if (!Tinode.topicType(topicName) || !this.tinode.isAuthenticated()) {
// Clear invalid topic name and hide messages view on mobile.
topicName = null;
newState.mobilePanel = 'sidepanel';