如何避免SolidJS页面切换时Home组件重渲染与重复API调用?
解决SolidJS路由返回时Home组件重复请求API的问题
核心原因
SolidJS默认路由行为是:每次导航到新路由时,原路由组件会被卸载;返回目标路由时,组件会重新挂载。这就导致Home组件的onMount在返回时再次执行,触发不必要的API调用。
解决方案
方案1:状态提升到路由外层(最简单可靠)
把items的状态移到路由的父组件(比如根组件App),这样Home组件卸载时状态不会丢失,返回时直接复用已有数据,无需重新请求。
修改根组件:
import { createSignal, onMount } from 'solid-js'; import { Routes, Route } from '@solidjs/router'; import Home from './Home'; import Detail from './Detail'; export default function App() { const [items, setItems] = createSignal<Item[]>([]); // 仅在App挂载时请求一次数据 onMount(async () => { setItems(await fetchItemsThroughExpensiveAPI()); }); return ( <Routes> <Route path="/" element={<Home items={items()} />} /> <Route path="/item/:id" element={<Detail />} /> </Routes> ); }
修改Home组件,移除内部状态,直接使用传入的props:
export default function Home(props: { items: Item[] }) { return ( <main> <For each={props.items}> {(item) => ( <A href={`/item/${item.id}`}>{item.name}</A> )} </For> </main> ); }
方案2:使用createResource缓存异步数据
SolidJS的createResource专门用于处理异步数据,自带缓存机制。只要请求的依赖项不变,组件重新挂载时不会重复发起请求。
修改Home组件:
import { createResource } from 'solid-js'; export default function Home() { // 依赖项设为固定值,确保仅请求一次 const [items] = createResource(() => true, async () => { return await fetchItemsThroughExpensiveAPI(); }); return ( <main> {/* 可根据需求添加加载状态提示 */} <For each={items() || []}> {(item) => ( <A href={`/item/${item.id}`}>{item.name}</A> )} </For> </main> ); }
方案3:手动实现组件缓存(Keep-Alive)
如果需要保留Home组件的实例(比如滚动位置、临时状态),可以手动实现缓存组件避免卸载。
创建KeepAlive组件:
import { createSignal, Show } from 'solid-js'; export default function KeepAlive(props: { children: JSX.Element }) { const [cached, setCached] = createSignal<JSX.Element | null>(null); setCached(() => props.children); return <Show when={cached()}>{cached()}</Show>; }
在路由中使用:
<Routes> <Route path="/" element={<KeepAlive><Home /></KeepAlive>} /> <Route path="/item/:id" element={<Detail />} /> </Routes>
注意:该方式会让Home组件常驻内存,适合需要保留组件状态的场景,需注意内存占用。
内容的提问来源于stack exchange,提问作者Simon Park
相关产品推荐
相关产品推荐

