javascriptreactjsnext.jsgraphqlapollo-client

next js 14 how to call graphql query as a ssr


I have created a next js project and setup apolo-client. I have rapped my children with it. this is my layout.tsx file code

import { Inter } from "next/font/google";
import "./globals.css";
import ApolloProviderClient from "@/components/ApolloProviderClient";

const inter = Inter({ subsets: ["latin"] });

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body className={inter.className}>
        <ApolloProviderClient>
          {children}
        </ApolloProviderClient>
      </body>
    </html>
  );
}

and ApolloProviderClient code -

"use client";

import { ApolloProvider } from "@apollo/client";
import { CheckoutProviderOwn } from "@/context/checkoutContextOwn";
import { SingleTimeLoader } from "@/components/singleTimeLoader/SingleTimeLoader";
import { client } from "@/utils/apollo-clients";

const ApolloProviderClient = ({ children }: { children: React.ReactNode }) => {
  return (
    <ApolloProvider client={client}>
      <CheckoutProviderOwn client={client}>
        <SingleTimeLoader />
        {children}
      </CheckoutProviderOwn>
    </ApolloProvider>
  );
};

export default ApolloProviderClient;`

and client code is this

import { ApolloClient, createHttpLink, InMemoryCache } from "@apollo/client";
import { setContext } from "@apollo/client/link/context";
import { baseUrl } from "@/utils/constant/baseUrl";

const httpLink = createHttpLink({
  uri: baseUrl,
});

const authLink = setContext((_, { headers }) => {
  const sessionToken = sessionStorage.getItem("accessToken");
  const localToken = localStorage.getItem("accessToken");
  const token = sessionToken || localToken;
  return {
    headers: {
      ...headers,
      Authorization: token ? `Bearer ${token}` : "",
    },
  };
});

export const client = new ApolloClient({
  link: authLink.concat(httpLink),
  cache: new InMemoryCache(),
});

so how can I create a ssr component & call a graphql api fetch data & display it without using "use client"

I wanted to create a product page where I want to so all the product with SSR because of SEO perpos.


Solution

  • You need slightly different setup for using apollo client with server pages. You will need to rewrite the components to use apollo client directly without relying on ApolloProvider context and useQuery hook. Here is a good artlice explaining how to do it.

    Here is a crud implementation (based on the article):

    
    // src/lib/client.ts
    
    import { ApolloClient, HttpLink, InMemoryCache } from "@apollo/client";
    import { registerApolloClient } from "@apollo/experimental-nextjs-app-support/rsc";
    
    export const { getClient } = registerApolloClient(() => {
      return new ApolloClient({
        cache: new InMemoryCache(),
        link: new HttpLink({
          uri: "put your api endpoint here",
        }),
      });
    });
    
    //src/lib/apollo-wrapper.ts
    "use client";
    
    import {
      ApolloClient,
      ApolloLink,
      HttpLink,
    } from "@apollo/client";
    import {
      ApolloNextAppProvider,
      NextSSRInMemoryCache,
      SSRMultipartLink,
    } from "@apollo/experimental-nextjs-app-support/ssr";
    
    function makeClient() {
      const httpLink = new HttpLink({
          uri: "put your api endpoint here",
      });
    
      return new NextSSRApolloClient({
        cache: new NextSSRInMemoryCache(),
        link:
          typeof window === "undefined"
            ? ApolloLink.from([
                new SSRMultipartLink({
                  stripDefer: true,
                }),
                httpLink,
              ])
            : httpLink,
      });
    }
    
    export function ApolloWrapper({ children }: React.PropsWithChildren) {
      return (
        <ApolloNextAppProvider makeClient={makeClient}>
          {children}
        </ApolloNextAppProvider>
      );
    }
    
    // src/app/layout.js
    import { ApolloWrapper } from "/@lib/apollo-wrapper";
    
    export default function RootLayout({
      children,
    }: {
      children: React.ReactNode,
    }) {
      return (
        <html lang="en">
          <body>
            <ApolloWrapper>{children}</ApolloWrapper>
          </body>
        </html>
      );
    }
    
    
    // here is a server component called UserProfile and here we want to get the user data
    
    import { gql } from "@apollo/client";
    import { getClient } from "@/lib/client";
    import { cookies } from "next/headers";
    
    
    const USER_QUERY = gql`
      query Query {
        user {
          id
          firstName
          email
          phone
        }
      }
    `;
    
    
    const UserProfile = async () => {
      const client = getClient();
      const ourCookies = cookies();
    
      let token = await ourCookies.get("jwtToken")!.value;
    
      let jwtToken = JSON.parse(token);
    
      const { data } = await client.query({
        query: USER_QUERY,
        context: {
          headers: {
            Authorization: `Bearer ${jwtToken}`,
          },
        },
      });
      console.log("🚀 ~ user ~ data:", data?.user);
      return (
        <>
          <h1>{data?.user?.firstName}</h1>
          <h2>{data?.user?.email}</h2>
        </>
      );
    };