Next.js Discord

Discord Forum

Best practise to fetch GraphQL data only once on a dynamic route and pass it to "generateMetadata"

Answered
Barbary Lion posted this in #help-forum
Open in Discord
Barbary LionOP
Hey, what is the best way to fetch GraphQL data via a dynamic route and then pass it to the main function of the server component as well as to "generateMetadata"?

On a dynamic route (app directory - page.tsx), I can access the "params" object only inside of "generateMetadata" and the default component, which results in having to perform two fetches. One inside of "generateMetadata" and one inside of the default component. But there must be a way to only fetch the data once and the pass it on to generateMetadata as well as the default component.

but how?
Answered by joulev
use React.cache to ensure the query only runs once despite being called multiple times.

import { cache } from 'react'
import db from '@/lib/db'
 
const getItem = cache(async (id: string) => {
  console.log("This is only run once");
  const item = await db.item.findUnique({ id })
  return item
})

export default async function Page() {
  const data = await getItem("foo");
  // ...
}

export async function generateMetadata() {
  const data = await getItem("foo");
  // ...
}
View full answer

7 Replies

@Barbary Lion Hey, what is the best way to fetch GraphQL data via a dynamic route and then pass it to the main function of the server component as well as to "generateMetadata"? On a dynamic route (app directory - page.tsx), I can access the "params" object only inside of "generateMetadata" and the default component, which results in having to perform two fetches. One inside of "generateMetadata" and one inside of the default component. But there must be a way to only fetch the data once and the pass it on to generateMetadata as well as the default component. but how?
use React.cache to ensure the query only runs once despite being called multiple times.

import { cache } from 'react'
import db from '@/lib/db'
 
const getItem = cache(async (id: string) => {
  console.log("This is only run once");
  const item = await db.item.findUnique({ id })
  return item
})

export default async function Page() {
  const data = await getItem("foo");
  // ...
}

export async function generateMetadata() {
  const data = await getItem("foo");
  // ...
}
Answer
Barbary LionOP
ok, thanks.
Well, I have cache activated in my ApolloClient. So I think this should than do the trick, too?

import { HttpLink } from "@apollo/client";
import {
  registerApolloClient,
  ApolloClient,
  InMemoryCache,
} from "@apollo/experimental-nextjs-app-support";

export const { getClient, query, PreloadQuery } = registerApolloClient(() => {
  return new ApolloClient({
    cache: new InMemoryCache(),
    link: new HttpLink({
      uri: "https://graphql.example.com/graphql",
    }),
  });
});
Barbary LionOP
ok, thanks. So the "correct way" is to work with a cache and there is no way to fetch the data in one place and pass it down to the other functions?
no. the two functions run independently so you cant pass data between them
Barbary LionOP
Thanks, got it