vercel / next.js

The React Framework
https://nextjs.org
MIT License
125.26k stars 26.77k forks source link

Router issue #59361

Open AndonMitev opened 9 months ago

AndonMitev commented 9 months ago

Verify canary release

Provide environment information

Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 23.1.0: Mon Oct  9 21:28:12 PDT 2023; root:xnu-10002.41.9~6/RELEASE_ARM64_T8103
Binaries:
  Node: 18.17.1
  npm: 9.6.7
  Yarn: 1.22.21
  pnpm: 8.7.6
Relevant Packages:
  next: 14.0.3
  eslint-config-next: 14.0.3
  react: 18.2.0
  react-dom: 18.2.0
  typescript: 5.3.2
Next.js Config:
  output: N/A

Which example does this report relate to?

app router

What browser are you using? (if relevant)

No response

How are you deploying your application? (if relevant)

No response

Describe the Bug

There is 1 route with 2 different query params:

http://localhost:3000/games?activeTab=trendy http://localhost:3000/games?activeTab=all

only activeTab is different, activeTab is managed by Link and query params are read trough searchParams as prop on page server component

when user is on http://localhost:3000/games?activeTab=trendy and refresh the page initially trendy is passed as query param but second later is changes to all automatically so basically after every refresh all is opened

Why is happening that what could cause such a behaviour

Expected Behavior

Not changing query params and stick to the one that is used when app is opened

To Reproduce

import Link from 'next/link';

const tabs = ['top', 'trending', 'new', 'all'];

interface TrendsTableTabsProps {
  activeTab: string;
}

function TrendsTableTabs({ activeTab }: TrendsTableTabsProps) {
  return (
    <div className='flex gap-[9px]'>
      {tabs.map((tab) => (
        <TabItem key={tab} tab={tab} activeTab={activeTab} />
      ))}
    </div>
  );
}

interface TabItemProps {
  tab: string;
  activeTab: string;
}

function TabItem({ tab, activeTab }: TabItemProps) {
  return (
    <div
      key={tab}
      className={`flex h-[45px] w-[102px] items-center justify-center gap-2 rounded-lg border bg-zinc-900 text-zinc-400 ${
        activeTab === tab ? 'border-sky-500' : 'border-neutral-800'
      }`}
    >
      <Link
        href={`?activeTab=${tab}`}
        className='h-full flex-1 pt-2 text-center align-middle capitalize'
        scroll={false}
        prefetch={false}
      >
        {tab}
      </Link>
    </div>
  );
}

export default TrendsTableTabs;

import it somewhere, navigate between different tabs and refresh the page all is being triggered all the time

KBeDevel commented 8 months ago

In server components, you need to use the searchParams property:

import Link from 'next/link';

const tabs = ['top', 'trending', 'new', 'all'];

interface TrendsTableTabsProps {
  searchParams: {
    activeTab: string;
  }
}

function TrendsTableTabs({ searchParams: { activeTab } }: TrendsTableTabsProps) {
  return (
    <div className='flex gap-[9px]'>
      {tabs.map((tab) => (
        <TabItem key={tab} tab={tab} activeTab={activeTab} />
      ))}
    </div>
  );
}

interface TabItemProps {
  tab: string;
  activeTab: string;
}

function TabItem({ tab, activeTab }: TabItemProps) {
  return (
    <div
      key={tab}
      className={`flex h-[45px] w-[102px] items-center justify-center gap-2 rounded-lg border bg-zinc-900 text-zinc-400 ${
        activeTab === tab ? 'border-sky-500' : 'border-neutral-800'
      }`}
    >
      <Link
        href={`?activeTab=${tab}`}
        className='h-full flex-1 pt-2 text-center align-middle capitalize'
        scroll={false}
        prefetch={false}
      >
        {tab}
      </Link>
    </div>
  );
}

export default TrendsTableTabs;

Ref: https://nextjs.org/docs/app/api-reference/file-conventions/page