You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js Router Cache缓存页面切换时能否保持React Context存活?

问题分析与解决办法

首先明确:Next.js的Router Cache缓存的是服务器组件(RSC)的输出和props,但客户端组件的状态(包括React Context)是存储在浏览器内存中的。当你切换路由时,原页面的客户端组件树会被完全卸载,Context自然会被销毁;导航回来时,客户端组件重新挂载,Context会重建,这就是你看到短暂空状态的原因。Router Cache无法保存客户端的Context状态,但可以通过以下几种方式规避空状态问题:

1. 将筛选/排序状态提升到全局客户端组件

把路由相关的筛选、排序状态放到根布局(layout.tsx)中的全局客户端组件里,这样路由切换时这个组件不会被卸载,状态得以保留。需要为不同路由单独存储状态:

// app/layout.tsx
'use client';

import { useState, usePathname } from 'react';
import { SortAndFilterProvider } from '@/components/providers';

export default function RootLayout({ children }) {
  // 存储各路由的筛选排序状态
  const [routeStates, setRouteStates] = useState({
    people: { filters: {}, pagination: {}, sort: {} },
    businesses: { filters: {}, pagination: {}, sort: {} },
  });

  const currentPath = usePathname();
  // 提取路由标识(如/people → people)
  const routeKey = currentPath.slice(1) || 'people';
  const currentState = routeStates[routeKey];

  // 更新当前路由的状态
  const updateRouteState = (newState) => {
    setRouteStates(prev => ({
      ...prev,
      [routeKey]: { ...currentState, ...newState },
    }));
  };

  // 传给Provider的状态值
  const sortAndFilterValue = {
    ...currentState,
    update: updateRouteState,
  };

  return (
    <html lang="zh-CN">
      <body>
        <SortAndFilterProvider value={sortAndFilterValue}>
          {children}
        </SortAndFilterProvider>
      </body>
    </html>
  );
}

然后修改Content组件,不再在内部创建状态,直接从全局Context获取:

// app/people/content.tsx
'use client';

import { useContext } from 'react';
import { SortAndFilterContext, DataProvider } from '@/components/providers';
import { useFilteredEntities } from '@/hooks';

const Content = ({ entities }) => {
  const sortAndFilter = useContext(SortAndFilterContext);
  const { filters, pagination, sort } = sortAndFilter;
  const searchableFields = ['name', 'role', 'businessName'];
  const data = useFilteredEntities({ filters, pagination, sort, entities, searchableFields });

  return (
    <DataProvider value={data}>
      <SearchPage />
    </DataProvider>
  );
};

2. 用缓存库缓存筛选后的数据

使用React Query或SWR这类客户端缓存库,把筛选计算后的结果缓存起来。即使Context重建,也能快速从缓存中读取数据,避免空状态:

// hooks/useFilteredEntities.ts
'use client';

import { useQuery } from '@tanstack/react-query';

export const useFilteredEntities = ({ filters, pagination, sort, entities, searchableFields }) => {
  // 构建唯一的缓存Key,包含路由、数据标识和筛选参数
  const queryKey = [
    'filtered-data',
    typeof window !== 'undefined' ? window.location.pathname : '',
    entities.length, // 用数据长度作为简易标识,也可以用数据的最后更新时间
    filters,
    pagination,
    sort,
    searchableFields,
  ];

  const { data } = useQuery({
    queryKey,
    queryFn: () => {
      // 这里放你的筛选、排序、分页逻辑
      let result = [...entities];
      // 应用筛选规则...
      // 应用排序规则...
      // 应用分页规则...
      return result;
    },
    staleTime: 30000, // 和Router Cache的30秒保持一致
    cacheTime: 30000,
  });

  // 缓存未就绪时返回原始数据,避免空状态
  return data || entities;
};

3. 给Context设置初始默认值

在DataProvider中直接用服务器传来的原始entities作为默认值,确保组件挂载时不会出现空状态:

// app/people/content.tsx
const Content = ({ entities }) => {
  const sortAndFilter = useSortAndFilter();
  const { filters, pagination, sort } = sortAndFilter;
  const searchableFields = ['name', 'role', 'businessName'];
  const data = useFilteredEntities({ filters, pagination, sort, entities, searchableFields });

  return (
    <SortAndFilterProvider value={sortAndFilter}>
      {/* 当data未就绪时,用原始entities兜底 */}
      <DataProvider value={data || entities}>
        <SearchPage />
      </DataProvider>
    </SortAndFilterProvider>
  );
};

内容的提问来源于stack exchange,提问作者jsindos

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 19:12:45