SPA 中:首页加载帖子列表,点击某帖跳转详情页(URL 变化),点击浏览器后退返回首页时,如何让列表内容保持原状、无需重新请求也无需重新渲染?请从路由机制、组件缓存、滚动恢复三方面说明原理,并分别给出 Vue 与 React 的实现。

核心矛盾:SPA 路由切换本质是组件卸载/挂载。默认情况下返回列表页 = 重新 mount = 重新发请求、重新渲染、滚动回到顶部。要做到"原样保留",需要三件套:组件实例缓存 + 数据状态外提 + 滚动位置恢复。

一、底层机制:URL 变化如何驱动视图

二、方案 A:组件缓存(Vue 推荐)

Vue 的 <keep-alive> 会缓存组件实例(连同 DOM 子树、data、滚动的 DOM 位置):

<router-view v-slot="{ Component }">
  <keep-alive :include="['Home']" :max="10">
    <component :is="Component" />
  </keep-alive>
</router-view>

三、方案 B:状态外提(React 常用)

React Router 默认没有 keep-alive,返回列表页必然重新 mount。常见做法:

  1. 把列表数据 + 筛选分页 + 滚动位置提升到全局 store(Redux / Zustand / Pinia),组件重新挂载时从 store 直接恢复,不发请求。
  2. "有缓存则不请求"约定:useEffect 里 if (store.list.length) return; fetch()。
  3. 想彻底保 DOM 可用第三方库 react-activation(KeepAlive 包裹),或手动维护一个"离屏容器"缓存列表 DOM。

四、滚动位置恢复

scrollBehavior(to, from, savedPosition) {
  return savedPosition || { top: 0 }
}

五、常见坑

同分类其他题目