Skip to content

fix: preserve route state when switching same-route tabs (dashboard time range resets) - #5796

Merged
Calcium-Ion merged 1 commit into
QuantumNous:mainfrom
feitianbubu:fix/tab-switch-resets-page-state
Jul 2, 2026
Merged

fix: preserve route state when switching same-route tabs (dashboard time range resets)#5796
Calcium-Ion merged 1 commit into
QuantumNous:mainfrom
feitianbubu:fix/tab-switch-resets-page-state

Conversation

@feitianbubu

@feitianbubu feitianbubu commented Jun 28, 2026

Copy link
Copy Markdown
Member

📝 变更描述 / Description

现象 / Symptom
在「数据看板」里选好一个时间范围(比如 7 天)后,点击同一个页面里的其它子标签(分流 / 用户统计),时间范围会悄悄跳回默认值;再切回来时范围和时间粒度也乱了。其它使用子标签的页面(使用日志、模型、系统设置)同样存在这种「切标签就丢状态」的问题。

原因 / Root cause
这些子标签本质上是同一个路由、只是 :section 参数不同(例如 /dashboard/$section)。负责页面切换动画的 AnimatedOutlet 把动画容器的 React key 设成了完整的 pathname。切换子标签时 pathname 变化 → key 变化 → React 会把整个页面卸载并重建,于是页面里用 useState 保存的筛选条件(时间范围等)全部丢失,回落到默认值。

旁证:开启系统「减少动画」的用户不会遇到这个问题,因为该分支不带 key、不会重挂。

修改 / Fix
key 改成「当前匹配到的路由 id」而不是完整 pathname:

// before —— 同路由换参数也会换 key,导致整页重挂
select: (s) => s.location.pathname,
// after —— 同路由内换参数 key 不变,跨页面才变
select: (s) => s.matches.at(-1)?.routeId ?? s.location.pathname,
  • 同一路由内只换参数(切子标签)→ key 不变 → 原地重渲染,组件状态保留;
  • 跳转到真正不同的页面 → 路由 id 变 → key 变 → 仍然播放进场动画。

🚀 变更类型 / Type of change

  • 🐛 Bug 修复 (Bug fix)
  • ✨ 新功能 (New feature)
  • ⚡ 性能优化 / 重构 (Refactor)
  • 📝 文档更新 (Documentation)

🔗 关联任务 / Related Issue

无单独 Issue(改动微小且自包含)。

✅ 提交前检查项 / Checklist

  • 人工确认: 描述为人工整理撰写。
  • 非重复提交: 已搜索现有 Issues 与 PRs,未发现重复。
  • Bug fix 说明: 确为行为缺陷(切换同路由子标签导致路由组件被重挂、状态丢失),非设计取舍。
  • 变更理解: 已理解其原理与影响。
  • 范围聚焦: 仅改动 1 个文件、5 行。
  • 本地验证: 见下方运行证明。
  • 安全合规: 无敏感凭据,符合规范。

📸 运行证明 / Proof of Work

数据看板-->选择7天, 点击分流 再点回来
修复前:
image
修复后:
image

Summary by CodeRabbit

  • Bug Fixes
    • Improved page transition behavior when navigating between routes that share the same route definition, so animations now restart more consistently for route changes with different parameters.

AnimatedOutlet keyed its motion container by the full pathname, so
navigating between params of the same route (e.g. the dashboard tabs
under /dashboard/$section) changed the key and remounted the route
component, discarding its in-memory state. The most visible symptom:
the dashboard time range resets to the default every time you switch
sub-tabs (Model Analytics / Flow / User Analytics).

Key the transition by the matched route id instead, so param-only
navigation re-renders in place while real page-to-page navigation
still plays the enter animation. This also preserves state across the
other $section tab pages (usage logs, models, system settings).
@coderabbitai

coderabbitai Bot commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

In AnimatedOutlet, the routeKey used to key page transitions is changed from location.pathname to the last matched route's routeId (with a location.pathname fallback), altering when the transition motion.div remounts during navigation.

Changes

Route-based page transition keying

Layer / File(s) Summary
routeKey uses routeId with pathname fallback
web/default/src/components/page-transition.tsx
routeKey now reads s.matches.at(-1)?.routeId instead of s.location.pathname, so transitions only restart when navigating between distinct route definitions, not on param-only changes.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~5 minutes

Poem

🐇 Hopping routes, same old trail,
No more flashing, no more flail!
routeId leads the bunny's way,
Params may change — transitions stay.
One smooth leap into the fray! 🌟

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly reflects the main bug fix: preserving state when switching tabs on the same route, including the dashboard time range reset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@Calcium-Ion
Calcium-Ion merged commit 759ab6b into QuantumNous:main Jul 2, 2026
2 checks passed
henrydontbbai added a commit to henrydontbbai/henry-newapi that referenced this pull request Jul 2, 2026
* feat: improve advanced custom route editor

* Bump Electron lockfile dependencies

* feat: bill doubao seedance-2.0 by output resolution and video input (QuantumNous#5300)

* feat: support doubao seedance 2.0 safety_identifier/priority and 4k billing (QuantumNous#5824)

* feat: support safety_identifier and priority for doubao video

* feat: add 4k resolution billing tier for doubao video

* chore: run `bun format` to automatically format the frontend code

* fix(web): 修复自定义 HTML 样式被过滤及排版间距异常的问题 (QuantumNous#5795)

* fix(web): 修复自定义 HTML 样式被过滤及排版间距异常的问题

* fix(web): isolate custom HTML rendering

---------

Co-authored-by: CaIon <i@caion.me>

* feat: support Wan2.7 i2v media mapping (QuantumNous#4984)

* feat: support Wan2.7 i2v media mapping

* fix: normalize wan2.7 i2v image inputs

* perf(web): optimize web Rsbuild and Tailwind build pipeline (QuantumNous#5786)

* fix(dev): run only default frontend in dev-web

- simplify make dev-web to install default dependencies and start web/default only.
- keep dev-web-classic as the standalone classic entry and scope its install to classic.

* chore(build): align make targets with web naming

- rename frontend make targets and variables to use the web terminology consistently.
- keep default and classic dev port overrides available under the updated names.

* fix(web): inject app styles into isolated HTML (QuantumNous#5860)

- clone loaded application style nodes into the Shadow DOM for custom HTML rendering.
- keep HTML rendering isolated while restoring layout and typography that depend on app CSS.

* fix: keep page state when switching tabs within the same route (QuantumNous#5796)

AnimatedOutlet keyed its motion container by the full pathname, so
navigating between params of the same route (e.g. the dashboard tabs
under /dashboard/$section) changed the key and remounted the route
component, discarding its in-memory state. The most visible symptom:
the dashboard time range resets to the default every time you switch
sub-tabs (Model Analytics / Flow / User Analytics).

Key the transition by the matched route id instead, so param-only
navigation re-renders in place while real page-to-page navigation
still plays the enter animation. This also preserves state across the
other $section tab pages (usage logs, models, system settings).

* 支持服务优雅关闭,避免重启回复中断和面板缓存数据丢失 (QuantumNous#4258)

* feat: add graceful shutdown with configurable timeout

* fix: flush quota dashboard cache on graceful shutdown

Persist the in-memory CacheQuotaData aggregation to the quota_data table
before process exit, so a restart no longer drops up to one DataExportInterval
window of dashboard data (issue QuantumNous#5679).

* docs: update AGENTS.md

* Make quota logging synchronous and delay startup log

---------

Co-authored-by: CaIon <i@caion.me>
Co-authored-by: feitianbubu <feitianbubu@qq.com>
Co-authored-by: t0ng7u <dev@aiass.cc>
Co-authored-by: olwater <52482488+olwater@users.noreply.github.com>
Co-authored-by: Scott <sc908181134@gmail.com>
Co-authored-by: QuentinHsu <xuquentinyang@gmail.com>
Co-authored-by: henrydontbbai <268972047+henrydontbbai@users.noreply.github.com>
liulixin-lex pushed a commit to liulixin-lex/xy-api that referenced this pull request Jul 7, 2026
…umNous#5796)

AnimatedOutlet keyed its motion container by the full pathname, so
navigating between params of the same route (e.g. the dashboard tabs
under /dashboard/$section) changed the key and remounted the route
component, discarding its in-memory state. The most visible symptom:
the dashboard time range resets to the default every time you switch
sub-tabs (Model Analytics / Flow / User Analytics).

Key the transition by the matched route id instead, so param-only
navigation re-renders in place while real page-to-page navigation
still plays the enter animation. This also preserves state across the
other $section tab pages (usage logs, models, system settings).
xiaomingchen pushed a commit to xiaomingchen/new-api that referenced this pull request Jul 10, 2026
…umNous#5796)

AnimatedOutlet keyed its motion container by the full pathname, so
navigating between params of the same route (e.g. the dashboard tabs
under /dashboard/$section) changed the key and remounted the route
component, discarding its in-memory state. The most visible symptom:
the dashboard time range resets to the default every time you switch
sub-tabs (Model Analytics / Flow / User Analytics).

Key the transition by the matched route id instead, so param-only
navigation re-renders in place while real page-to-page navigation
still plays the enter animation. This also preserves state across the
other $section tab pages (usage logs, models, system settings).
Jacobinwwey pushed a commit to Jacobinwwey/new-api that referenced this pull request Jul 11, 2026
…umNous#5796)

AnimatedOutlet keyed its motion container by the full pathname, so
navigating between params of the same route (e.g. the dashboard tabs
under /dashboard/$section) changed the key and remounted the route
component, discarding its in-memory state. The most visible symptom:
the dashboard time range resets to the default every time you switch
sub-tabs (Model Analytics / Flow / User Analytics).

Key the transition by the matched route id instead, so param-only
navigation re-renders in place while real page-to-page navigation
still plays the enter animation. This also preserves state across the
other $section tab pages (usage logs, models, system settings).
ruanhangjian pushed a commit to ruanhangjian/new-api that referenced this pull request Jul 11, 2026
…umNous#5796)

AnimatedOutlet keyed its motion container by the full pathname, so
navigating between params of the same route (e.g. the dashboard tabs
under /dashboard/$section) changed the key and remounted the route
component, discarding its in-memory state. The most visible symptom:
the dashboard time range resets to the default every time you switch
sub-tabs (Model Analytics / Flow / User Analytics).

Key the transition by the matched route id instead, so param-only
navigation re-renders in place while real page-to-page navigation
still plays the enter animation. This also preserves state across the
other $section tab pages (usage logs, models, system settings).
noah-wung pushed a commit to noah-wung/new-api that referenced this pull request Jul 17, 2026
…umNous#5796)

AnimatedOutlet keyed its motion container by the full pathname, so
navigating between params of the same route (e.g. the dashboard tabs
under /dashboard/$section) changed the key and remounted the route
component, discarding its in-memory state. The most visible symptom:
the dashboard time range resets to the default every time you switch
sub-tabs (Model Analytics / Flow / User Analytics).

Key the transition by the matched route id instead, so param-only
navigation re-renders in place while real page-to-page navigation
still plays the enter animation. This also preserves state across the
other $section tab pages (usage logs, models, system settings).
zhaodechao2008 pushed a commit to zhaodechao2008/new-api that referenced this pull request Jul 27, 2026
…umNous#5796)

AnimatedOutlet keyed its motion container by the full pathname, so
navigating between params of the same route (e.g. the dashboard tabs
under /dashboard/$section) changed the key and remounted the route
component, discarding its in-memory state. The most visible symptom:
the dashboard time range resets to the default every time you switch
sub-tabs (Model Analytics / Flow / User Analytics).

Key the transition by the matched route id instead, so param-only
navigation re-renders in place while real page-to-page navigation
still plays the enter animation. This also preserves state across the
other $section tab pages (usage logs, models, system settings).
330079598 pushed a commit to 330079598/new-api that referenced this pull request Aug 19, 2026
…umNous#5796)

AnimatedOutlet keyed its motion container by the full pathname, so
navigating between params of the same route (e.g. the dashboard tabs
under /dashboard/$section) changed the key and remounted the route
component, discarding its in-memory state. The most visible symptom:
the dashboard time range resets to the default every time you switch
sub-tabs (Model Analytics / Flow / User Analytics).

Key the transition by the matched route id instead, so param-only
navigation re-renders in place while real page-to-page navigation
still plays the enter animation. This also preserves state across the
other $section tab pages (usage logs, models, system settings).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants