performancenext.jscachingserver-side-renderingapp-router

How can I persist data in client side while using SSR in Next 14.1?


This is the situation:

I have a project where I use SSR to fetch the info and pass it as props to my client components; there, I initialize an state with the prop data, so I can use that state from useState to whatever I want.

My question is: I feel that navigating throught the pages under a root layout (app/manage/[slug], where manage has a layout.tsx file, and under [slug] I have some other sub routes) is really slow sometimes.

This is a page.tsx file under /[slug]:

/app/manage/[slug]/tenants (page.tsx)

export default async function Page({ params }: { params: any }) {
  const supabase = createClient();
  const { data: manager } = await supabase
    .from('managers')
    .select()
    .eq('slug', params?.slug)
    .single();
  const properties = await getPropertiesWithEnvelope(manager);

  const tenantsData = await getTenants(manager);
  return <ManageComp tenantsData={tenantsData} properties={properties} />;
}

and this is the ManageComp that the above page.tsx returns: /app/manage/[slug]/tenants (ManageComp.tsx)

export default function ManageComp({ properties, tenantsData }: any) {
  const [progress, setProgress] = React.useState(0);
  const [tenants, setTenants] = React.useState<any>(tenantsData || []);

  const fetchTenants = async () => {
    setProgress(50);
    const tenants = await getTenants(manager);
    setTenants(tenants);
    setProgress(100);
  };
  return (
    <Wrapper
      gapCondition={tenantsData.length}
      section="Tenants"
      headerActions={
        <AddTenant
          fetchTenants={fetchTenants}
          properties={properties}
        />
      }
    >
      <LoadingBar
        color={'#00712D'}
        progress={progress}
        onLoaderFinished={() => setProgress(0)}
      />
      <CardGrid
        emptyStateSubtitle="Add your first tenant now and take control of your rental management journey."
        emptyStateTitle="Start Building Your Tenant List"
        condition={tenants.length > 0}
        image={noTenantsIlustration}
        component={
          <AddTenant
            fetchTenants={fetchTenants}
            properties={properties}
          />
        }
      >
        {tenants.map((tenant: any) => {
          let status = getTenantStatus({ tenant });
          return (
            <React.Fragment key={tenant.id}>
              <TenantCard
                id={tenant.id}
                tenant={tenant}
                status={status}
                properties={properties}
                last_modified=""
                fetchTenants={fetchTenants}
              />
            </React.Fragment>
          );
        })}
      </CardGrid>
    </Wrapper>
  );
}

As you can see, Im not fetching too much in the server to make it take 3s~ to load the page.

In summary my question is:

I tried using force dynamic int he page.tsx, also revalidate=0.

I wouldn't like to use a global state management (like zustand) but just because even when using it, next sometimes caches the server info (so navigation is fast) but sometimes it fetches again the info to supabase, so this make that slower.


Solution

  • Good question, its explained in this Next documentation and you could potentially cache the returned data from supabase by following this

    NextJS automatically implements different caching strategies depending on app/api usage though and I think it would make sense to keep the DB query like it is. Nowadays though, you could pass those requests promises to the children client components and render something while those finish fullfilling, using React.use()

    And if you really need to re-fetch every time, you could be following any of the revalidation options they give, examples here

    Hope this helped😁