Next 14.1 SSR场景下客户端数据持久化与导航优化方案
解决方案:优化SSR数据获取与缓存,提升子路由导航速度
1. 服务器端:配置合理缓存策略,减少重复请求
你之前用force dynamic和revalidate=0会完全禁用缓存,导致每次导航都重新请求Supabase。可以针对性调整缓存规则,平衡数据新鲜度和加载速度:
调整页面缓存有效期
在子路由page.tsx中设置revalidate,根据数据更新频率配置缓存时长(比如60秒,可按需调整):
// app/manage/[slug]/tenants/page.tsx export const revalidate = 60; // 缓存60秒,到期自动重新拉取最新数据 export default async function Page({ params }: { params: any }) { const supabase = createClient(); // 给Supabase请求添加缓存配置,利用HTTP缓存机制 const { data: manager } = await supabase .from('managers') .select() .eq('slug', params?.slug) .single() .option({ cache: 'force-cache' }); const properties = await getPropertiesWithEnvelope(manager); const tenantsData = await getTenants(manager); return <ManageComp tenantsData={tenantsData} properties={properties} manager={manager} />; }
父路由预取共享数据
将manager、properties这类跨子路由共享的数据,放到父路由layout.tsx中统一获取,避免每个子路由重复发起相同请求:
// app/manage/[slug]/layout.tsx export const revalidate = 60; export default async function ManageLayout({ children, params, }: { children: React.ReactNode; params: { slug: string }; }) { const supabase = createClient(); const { data: manager } = await supabase .from('managers') .select() .eq('slug', params.slug) .single() .option({ cache: 'force-cache' }); const properties = await getPropertiesWithEnvelope(manager); // 将共享数据传递给所有子路由页面 return ( <div> {React.cloneElement(children as React.ReactElement, { manager, properties })} </div> ); }
子路由page.tsx可简化为:
// app/manage/[slug]/tenants/page.tsx export const revalidate = 60; export default async function Page({ manager, properties }: { manager: any; properties: any }) { const tenantsData = await getTenants(manager); return <ManageComp tenantsData={tenantsData} properties={properties} manager={manager} />; }
2. 客户端:本地缓存快速初始化状态,后台更新
不用全局状态管理,可通过sessionStorage临时缓存数据,切换路由时先加载缓存数据渲染页面,再后台静默更新最新数据:
// app/manage/[slug]/tenants/ManageComp.tsx export default function ManageComp({ properties, tenantsData, manager }: any) { const [progress, setProgress] = React.useState(0); // 优先从sessionStorage加载缓存数据,无缓存则用SSR传递的props const [tenants, setTenants] = React.useState<any>(() => { const cacheKey = `tenants_${manager.id}`; const cachedData = sessionStorage.getItem(cacheKey); return cachedData ? JSON.parse(cachedData) : tenantsData || []; }); // 组件挂载后后台更新最新数据,不阻塞页面渲染 React.useEffect(() => { const updateTenants = async () => { setProgress(50); const freshTenants = await getTenants(manager); setTenants(freshTenants); sessionStorage.setItem(`tenants_${manager.id}`, JSON.stringify(freshTenants)); setProgress(100); }; updateTenants(); }, [manager.id]); const fetchTenants = async () => { setProgress(50); const freshTenants = await getTenants(manager); setTenants(freshTenants); sessionStorage.setItem(`tenants_${manager.id}`, JSON.stringify(freshTenants)); setProgress(100); }; // 原JSX代码保持不变 }
3. 优化数据获取逻辑:合并请求减少网络开销
如果getPropertiesWithEnvelope和getTenants内部包含多个独立Supabase请求,可以尝试合并为批量请求(比如用Supabase的rpc函数、批量查询),减少网络往返次数,降低整体请求耗时。
内容的提问来源于stack exchange,提问作者Gaston Jacinto
相关产品推荐
相关产品推荐

