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

Next.js 14中如何在不暴露URL的情况下实现页面间数据传递?

在Next.js 14 App目录下实现无URL暴露的页面间数据传递

针对你的需求(用自定义Button导航,不把数据暴露在URL中传递),这里提供三种实用方案:


方案一:Server Actions + 服务器临时存储

适合需要服务器端处理数据的场景,通过临时索引映射数据,避免敏感信息出现在URL中。

步骤1:创建Server Action管理临时数据

在app/actions.ts中定义存储和读取数据的服务端逻辑:

'use server';
import { cache } from 'react';

// 内存缓存仅用于开发,生产环境建议替换为Redis等持久化存储
const tempDataStore = new Map<string, string>();

export async function setTempData(key: string, value: string) {
  tempDataStore.set(key, value);
  // 1分钟后自动清理数据,防止内存泄漏
  setTimeout(() => tempDataStore.delete(key), 60000);
}

export const getTempData = cache(async function getTempData(key: string) {
  return tempDataStore.get(key);
});

步骤2:修改Page1的导航逻辑

在page1/page.tsx中,先调用Server Action存储数据,再携带临时索引跳转:

'use client';
import { Button } from '@/components/Button';
import { setTempData } from '@/app/actions';
import { useRouter } from 'next/navigation';

export default function Page1() {
  const router = useRouter();

  const handleNavigate = async () => {
    // 生成唯一临时索引
    const dataKey = Date.now().toString();
    await setTempData(dataKey, 'Johndeo');
    // 仅传递索引,不暴露真实数据
    router.push(`/mypage2?dataKey=${dataKey}`);
  };

  return (
    <div>
      <Button onClick={handleNavigate}>Go to page2</Button>
    </div>
  );
}

步骤3:在Page2中读取数据

在page2/page.tsx中通过索引获取服务器存储的数据:

import { getTempData } from '@/app/actions';
import { Suspense } from 'react';

async function DataDisplay({ searchParams }: { searchParams: { dataKey?: string } }) {
  if (!searchParams.dataKey) return <div>No data received</div>;
  const name = await getTempData(searchParams.dataKey);
  return <div>Name: {name}</div>;
}

export default function Page2() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <DataDisplay />
    </Suspense>
  );
}

方案二:客户端状态管理(React Context + SessionStorage)

适合纯客户端场景,数据仅存在浏览器端,完全不修改URL。

步骤1:创建导航数据Context

在app/navigationData.tsx中实现全局状态管理:

'use client';
import { createContext, useContext, useState, useEffect } from 'react';

interface NavigationDataContextType {
  setNavigationData: (data: any) => void;
  getNavigationData: () => any;
  clearNavigationData: () => void;
}

const NavigationDataContext = createContext<NavigationDataContextType | undefined>(undefined);

export function NavigationDataProvider({ children }: { children: React.ReactNode }) {
  const [data, setData] = useState<any>(null);

  useEffect(() => {
    // 页面加载时读取并清除SessionStorage中的数据
    const savedData = sessionStorage.getItem('navigationData');
    if (savedData) {
      setData(JSON.parse(savedData));
      sessionStorage.removeItem('navigationData');
    }
  }, []);

  const setNavigationData = (newData: any) => {
    sessionStorage.setItem('navigationData', JSON.stringify(newData));
    setData(newData);
  };

  const getNavigationData = () => data;

  const clearNavigationData = () => {
    setData(null);
    sessionStorage.removeItem('navigationData');
  };

  return (
    <NavigationDataContext.Provider value={{ setNavigationData, getNavigationData, clearNavigationData }}>
      {children}
    </NavigationDataContext.Provider>
  );
}

export const useNavigationData = () => {
  const context = useContext(NavigationDataContext);
  if (!context) {
    throw new Error('useNavigationData must be used within a NavigationDataProvider');
  }
  return context;
};

步骤2:在根布局中注入Provider

修改app/layout.tsx,用Provider包裹整个应用:

import { NavigationDataProvider } from './navigationData';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <NavigationDataProvider>{children}</NavigationDataProvider>
      </body>
    </html>
  );
}

步骤3:Page1中设置数据并跳转

'use client';
import { Button } from '@/components/Button';
import { useNavigationData } from '@/app/navigationData';
import { useRouter } from 'next/navigation';

export default function Page1() {
  const { setNavigationData } = useNavigationData();
  const router = useRouter();

  const handleNavigate = () => {
    setNavigationData({ name: 'Johndeo' });
    router.push('/mypage2');
  };

  return (
    <div>
      <Button onClick={handleNavigate}>Go to page2</Button>
    </div>
  );
}

步骤4:Page2中读取并清理数据

'use client';
import { useNavigationData } from '@/app/navigationData';
import { useEffect } from 'react';

export default function Page2() {
  const { getNavigationData, clearNavigationData } = useNavigationData();
  const navigationData = getNavigationData();

  useEffect(() => {
    // 页面卸载时清除数据,避免刷新后残留
    return () => clearNavigationData();
  }, [clearNavigationData]);

  return (
    <div>
      {navigationData ? <div>Name: {navigationData.name}</div> : <div>No data received</div>}
    </div>
  );
}

方案三:Cookie存储

适合需要服务器端和客户端都能访问数据的场景,数据存在Cookie中,URL无敏感信息。

步骤1:Page1中设置Cookie并跳转

'use client';
import { Button } from '@/components/Button';
import { useRouter } from 'next/navigation';

export default function Page1() {
  const router = useRouter();

  const handleNavigate = () => {
    // 设置Cookie,1分钟后过期
    document.cookie = `navName=Johndeo; path=/; max-age=60; SameSite=Lax`;
    router.push('/mypage2');
  };

  return (
    <div>
      <Button onClick={handleNavigate}>Go to page2</Button>
    </div>
  );
}

步骤2:Page2中读取并清理Cookie

客户端读取:

'use client';
import { useEffect, useState } from 'react';

export default function Page2() {
  const [name, setName] = useState<string | null>(null);

  useEffect(() => {
    // 解析Cookie
    const cookies = document.cookie.split('; ');
    const navNameCookie = cookies.find(c => c.startsWith('navName='));
    if (navNameCookie) {
      setName(navNameCookie.split('=')[1]);
      // 读取后立即删除Cookie
      document.cookie = `navName=; path=/; max-age=0`;
    }
  }, []);

  return <div>Name: {name || 'No data'}</div>;
}

服务器端读取(适合服务器组件):

import { cookies } from 'next/headers';

export default function Page2() {
  const cookieStore = cookies();
  const name = cookieStore.get('navName')?.value;
  
  return (
    <div>
      <div>Name: {name || 'No data'}</div>
      <form action={clearNavNameCookie}>
        <button type="submit">Clear Cookie</button>
      </form>
    </div>
  );
}

'use server';
export async function clearNavNameCookie() {
  cookies().delete('navName');
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 14:57:43