
SolidJS Router 默认卸载离开的页面组件,导致 history.back() 时重新挂载。本文介绍如何通过 createRoot 手动管理组件生命周期,实现页面状态持久化与高效复用。
solidjs router 默认卸载离开的页面组件,导致 `history.back()` 时重新挂载。本文介绍如何通过 `createroot` 手动管理组件生命周期,实现页面状态持久化与高效复用。
在 SolidJS 中,Router 的设计哲学是按需渲染、严格隔离:每当导航离开某一路由,其对应组件会被完全卸载(disposal),所有响应式依赖、副作用(如 onMount、onCleanup)均被清除。这虽保障了状态纯净性与内存安全,但在多页频繁往返(如“首页 → 用户页 → 返回首页”)场景下,会导致不必要的重复初始化、状态丢失和性能损耗。
要解决此问题,核心思路是绕过 Router 的自动销毁机制,将目标组件提前“脱离”当前响应式上下文,转为由开发者手动控制其生命周期。SolidJS 提供的 createRoot 正是为此而生——它创建一个独立的、不受父级信号影响的响应式根,并返回一个可手动调用的 dispose 函数。
以下为推荐实现方案:
import {
Link, Route, Router, Routes,
hashIntegration
} from '@solidjs/router';
import { Component, createRoot, onMount, onCleanup } from 'solid-js';
import { render } from 'solid-js/web';
// 示例页面组件(含副作用)
const Home = () => {
onMount(() => console.log('Home mounted — state preserved!'));
onCleanup(() => console.log('Home cleanup — will NOT trigger on back()'));
// ✅ 假设此处有表单输入、滚动位置、加载状态等需保留的数据
return <div class="page-home">? Home Page (cached)</div>;
};
// 使用 createRoot 将组件“冻结”为静态根实例
let disposeHome: () => void;
const MemoizedHome = createRoot((disposer) => {
disposeHome = disposer;
return <home></home>;
}) as unknown as Component;
// ⚠️ 注意:不要在组件内部调用 dispose!仅在真正需要释放时(如应用卸载)调用
// 这里仅为演示,实际项目中建议结合路由守卫或全局状态管理决定 dispose 时机
if (typeof window !== 'undefined') {
window.addEventListener('beforeunload', () => disposeHome?.());
}
const App = () => (
<router source="{hashIntegration()}"><nav><ul style="{{" display: gap: padding:>
<li>
<link href="/home">Home</li>
<li>
<link href="/user">User</li>
<li>
<link href="/about">About</li>
</ul></nav><main style="{{" padding:><routes><route path="/home" component="{MemoizedHome}"></route><route path="/user" component="{()"><div class="page-user">? User Page</div>} />
<route path="/about" component="{()"><div class="page-about">ℹ️ About</div>} />
</route></route></routes></main></router>
);
render(App, document.getElementById('root')!);
✅ 关键要点说明:
- createRoot 返回的是一个纯函数组件引用,而非 JSX 元素,因此可安全传入
; - 组件内部的 onMount 仅在首次挂载时执行,后续 history.back() 或路由跳转返回时不会重复触发,onCleanup 也仅在显式调用 dispose() 时运行;
- 所有响应式状态(createStore、createSignal 等)及 DOM 节点均被保留,实现真正的“页面缓存”;
- 若需在特定条件下(如用户登出、切换主题)强制刷新某页面,可暴露 disposeHome 并主动调用,再重新 createRoot;
- 不推荐对所有页面无差别缓存——应按需应用(如表单页、数据看板页),避免内存累积。
? 替代方案对比:
- createMemo 仅缓存计算值,无法保留组件树与副作用;
- 第三方库(如 solid-router-cache)尚不成熟,官方未内置缓存策略;
- useTransition 或 Suspense 解决的是加载态问题,不改变卸载行为。
综上,createRoot 是当前 SolidJS 生态中最轻量、最可控、且符合响应式范式的页面复用方案。合理运用它,即可在保持框架简洁性的同时,精准满足复杂 SPA 的用户体验需求。











