Next.js Discord

Discord Forum

Navigating between two client component tabs causes data to reload each time

Unanswered
Tonkinese posted this in #help-forum
Open in Discord
TonkineseOP
Hey guys, i'm implementing the Nested Layouts pattern from https://app-router.vercel.app/layouts, but I'm coming up against this weird scenario where when I navigate back and forth between my Products and Groups tabs, the loading skeleton appears every time, and I don't understand why.

--- store/[id]/layout.tsx ---
const tabs = [
    { name: "Bar", slug: "bar" },
    { name: "Baz", slug: "baz" },
  ];

export default async function Layout() {
  ...

  return (
    <>
      <div className="flex-col space-y-4 tiny:px-4">
        <TabGroup
          path={`/store/${params.slug}`}
          items={[
            { text: "Foo" },
            ...tabs.map((x) => ({
              text: x.name,
              slug: x.slug,
            })),
          ]}
        />
      </div>
      
      <div className="flex justify-center w-full">{children}</div>
    </>
  )
}

--- store/[id]/page.tsx ---
export default async function Page(props: { params: Promise<{ slug: string }> }) {
  const params = await props.params;

  return <FooTab slug={params.slug} />;
}

8 Replies

TonkineseOP
--- foo-tab.tsx ---
"use client";

import { Suspense } from "react";
import { useSuspenseQuery } from "@apollo/client";

import { getFoo } from "@/queries/getFoo";
import { Foo } from "@/components/Foo";
import { FooSkeleton } from "@/components/FooSkeleton";

interface TabContentProps {
  slug: string;
}

function TabContent({ id }: TabContentProps) {
  const result = useSuspenseQuery(getFoo, {
    variables: {
      slug: slug,
    },
  });

  const { data, loading }: any = result;

  if (loading) {
    return <FooSkeleton />;
  }

  const store = data.store.edges[0]?.node;
  const nodes = store.foo.edges.map((edge: any) => edge.node);
  const pageInfo = store.foo.pageInfo;

  return <Foo result={{ ...result }} nodes={nodes} pageInfo={pageInfo} />;
}

interface FooTabProps {
  slug: string;
}

export const FooTab = ({ id }: FooTabProps) => {
  return (
    <Suspense fallback={<FooSkeleton />}>
      <TabContent id={slug} />
    </Suspense>
  );
};

--- bar-tab.tsx ---
(same as foo-tab.tsx, but with groups data)
I'm trying to get it so that the loading skeletons only appear the first time you click a particular tab, but all subsequent clicks on that tab should show the rendered content
TonkineseOP
I noticed this happens if i navigate between the foo and bar tabs, which both make queries. But if i only navigate between one of those two tabs and the baz tab (which makes zero queries and just uses a static javascript object), then the query tab no longer shows a loading skeleton when navigating back to it
so for some reason switching between those two query tabs is messing with the way that next caches content?
ok I made a further discovery: it seems if I make any apollo query (or mutation) on that root layout, then the contents of the foo and bar tabs will reload when next navigating to them
TonkineseOP
apparently caused by using <Suspense> to wrap my tab content in conjunction with apollo client
removing the Suspense fixed the issue
If this is solved please mark your answer as solved