reactjsnext.jscomponentsnextjs14

How to pass data using Next.js Link component without showing it in the URL?


I'm currently working on a Next.js application and I need to navigate between pages while passing some data without exposing it in the URL. I know that the Link component from Next.js allows me to navigate between pages, but I’m unsure how to achieve this without appending the data to the URL.

import Link from 'next/link';

const SourceComponent = () => {
  const dataToPass = { key: 'value' };

  return (
    <Link href="/target-page" passHref>
      <a>{/* Some content */}</a>
    </Link>
  );
};

In this example, the data is not passed to the target-page. I want to access the "dataToPass" on targeted page.

I also tried using router.push to navigate programmatically:

import Link from 'next/link';

import { useRouter } from 'next/router';

const SourceComponent = () => {
  const router = useRouter();
  const dataToPass = { key: 'value' };

  const handleClick = () => {
    router.push({
      pathname: '/target-page',
      query: { data: JSON.stringify(dataToPass) }, // This exposes the data in the URL
    });
  };
  return (
    <button onClick={handleClick}>Go to Target Page</button>
  );
};

In this case, I noticed that the data still gets appended to the URL.

Thank you for your help!


Solution

  • The answer depends on your use case and what kind of data you want to pass. One way is using React Context API for sharing data between pages.

    Assuming you are using NextJS with App Router, you need to create a context provider component and wrap your application with it.

    // src/providers/EnvironmentProvider.tsx
    
    'use client';
    
    import {
      ReactNode,
      createContext,
      useContext,
      useMemo
    } from 'react';
    
    
    type EnvironmentContextType = {
      data: any;
      setData: (params: any) => void;
    };
    
    const ENVIRONMENT_CONTEXT_DEFAULT_VALUES: EnvironmentContextType = {
      data: {},
      setData: () => {}
    };
    
    const EnvironmentContext = createContext(ENVIRONMENT_CONTEXT_DEFAULT_VALUES);
    
    export const useEnvironment = () => useContext(EnvironmentContext);
    
    type EnvironmentProviderProps = {
      children: ReactNode;
    };
    
    export const EnvironmentProvider = ({
      children
    }: EnvironmentProviderProps) => {
      const [data, setData] = useState<any>({});
    
      const values: EnvironmentContextType = useMemo(() => ({
        data,
        setData
      }), []);
    
      return ( <
        EnvironmentContext.Provider value={
          values
        }>{
          children
        }<
        /EnvironmentContext.Provider>
      );
    };

    // src/app/layout.tsx
    
    import { EnvironmentProvider } from '@/providers/EnvironmentProvider';
    
    export default function RootLayout({
      children,
    }: {
      children: React.ReactNode;
    }) {
      return (
        <html lang="en">
          <head>
            <link rel="manifest" href="/manifest.json" />
          </head>
    
          <body>
            <EnvironmentProvider>
              {children}
            </EnvironmentProvider>
          </body>
        </html>
      );
    }

    Consider replacing any with the correct types (or remove any typing if use use JS).

    Updated SourceComponent and TargetComponent:

    import Link from 'next/link';
    
    import { useRouter } from 'next/router';
    
    import { useEnvironment } from '@/providers/EnvironmentProvider';
    
    const SourceComponent = () => {
      const router = useRouter();
      const { setData } = useEnvironment();
      const dataToPass = { key: 'value' };
    
      const handleClick = () => {
        setData(dataToPass);
    
        router.push({
          pathname: '/target-page',
        });
      };
      return (
        <button onClick={handleClick}>Go to Target Page</button>
      );
    };
    
    const TargetComponent = () => {
      const { data } = useEnvironment();
    
      return (
        <h1>{data.key}</h1>
      );
    };

    More detailed guide from Vercel Using React Context for State Management with Next.js.