Search code examples
javascriptreactjsnext.jsgraphql

graphql api fetching issue in next js getting ( Error: React functionality 'useContext' is not available in this environment. )


I have created a next js 14.2.3 app & I have graphql api end point(** which I replaced with localhost for stackOverflow )and I am using "@apollo/client":"^3.10.3", "graphql":"^16.8.1", for fetching data. I have created a product page path "pages/products".

import { useQuery, gql } from "@apollo/client";
import { initializeApollo } from "../lib/apollo-client";

const PRODUCTS_QUERY = gql`
  query Products {
    products(first: 10, channel: "default-channel") {
      edges {
        node {
          id
          name
        }
      }
    }
  }
`;

function Products() {
  const apolloClient = initializeApollo();
  const { data, loading, error } = useQuery(PRODUCTS_QUERY, {
    client: apolloClient,
  });

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error: {error.message}</p>;

  return (
    <div>
      <h1>Products</h1>
      <ul>
        {data &&
          data.products.edges.map(({ node }) => (
            <li key={node.id}>{node.name}</li>
          ))}
      </ul>
    </div>
  );
}

export default Products;

I have created a apollo-client,js file

import { useMemo } from "react";
import { ApolloClient, HttpLink, InMemoryCache } from "@apollo/client";

let apolloClient;

function createApolloClient() {
  return new ApolloClient({
    ssrMode: typeof window === "undefined",
    link: new HttpLink({
      uri: "http://localhost:8000/graphql/",
    }),
    cache: new InMemoryCache(),
  });
}

export function initializeApollo(initialState = null) {
  const _apolloClient = apolloClient ?? createApolloClient();

  // If your page has Next.js data fetching methods that use Apollo Client, the initial
  state;
  // gets hydrated here
  if (initialState) {
    _apolloClient.cache.restore(initialState);
  }
  // For SSG and SSR always create a new Apollo Client
  if (typeof window === "undefined") return _apolloClient;
  // Create the Apollo Client once in the client
  if (!apolloClient) apolloClient = _apolloClient;

  return _apolloClient;
}

export function useApollo(initialState) {
  const store = useMemo(() => initializeApollo(initialState), [initialState]);
  return store;
}

so when I am routing http://localhost:3000/pages/products

getting error - enter image description here


Solution

  • I think this is because <Products /> component currently rendered as server component. And Contexts is not avaliable for server components.

    There are two ways to fix it:

    1. is to make this component client by adding "use client" on top of pages/products.

    2. Rewrite the component to use apollo client directly without relying on useQuery hook. Here is a good artlice explaining how to do it.

    Crud example:

    import { gql } from "@apollo/client";
    import { initializeApollo } from "../lib/apollo-client";
    
    const PRODUCTS_QUERY = gql`
      query Products {
        products(first: 10, channel: "default-channel") {
          edges {
            node {
              id
              name
            }
          }
        }
      }
    `;
    
    async function Products() {
      const apolloClient = initializeApollo();
      const { data } = await apolloClient.query({
        query: PRODUCTS_QUERY,
        context: {},
      });
    
      return (
        <div>
          <h1>Products</h1>
          <ul>
            {data?.products?.edges?.map(({ node }) => (
              <li key={node.id}>{node.name}</li>
            ))}
          </ul>
        </div>
      );
    }
    export default Products;