Giter VIP home page Giter VIP logo

Invariant Violation: An error occurred! For more details, see the full error text at https://go.apollo.dev/c/err#%7B%22version%22%3A%223.9.4%22%2C%22message%22%3A49%2C%22args%22%3A%5B%5D%7D about apollo-client HOT 8 CLOSED

MarvinTchio avatar MarvinTchio commented on May 25, 2024
Invariant Violation: An error occurred! For more details, see the full error text at https://go.apollo.dev/c/err#%7B%22version%22%3A%223.9.4%22%2C%22message%22%3A49%2C%22args%22%3A%5B%5D%7D

from apollo-client.

Comments (8)

phryneas avatar phryneas commented on May 25, 2024 1

One more comment here:

export function makeClient() {
  // Adjust to use NextSSRApolloClient for SSR with appropriate caching and link setup
  return new NextSSRApolloClient({
    link: typeof window === "undefined"
      ? ApolloLink.from([new SSRMultipartLink({ stripDefer: true }), httpLink])
      : httpLink,
-    cache: new InMemoryCache(),
+   cache: new NextSSRInMemoryCache()
  });
}

Apart from that, I think at this point you're set up correctly :)

I think your questions here are solved, so I'm closing this issue.

Generally, if you have usage questions like this, please consider asking in the Apollo GraphQL Discord first - the issue tracker here is meant more for bug reports.

from apollo-client.

phryneas avatar phryneas commented on May 25, 2024

It seems like you do not have an <ApolloProvider in your application.

Generally, please note that you should not be using @apollo/client on it's own in the app directory.

We have a separate package to integrate Apollo Client with the Next.js app router:

https://www.apollographql.com/blog/using-apollo-client-with-next-js-13-releasing-an-official-library-to-support-the-app-router

from apollo-client.

MarvinTchio avatar MarvinTchio commented on May 25, 2024

Now I have the following set up and the error I'm facing is : - Screenshot 2024-02-14 at 4 37 58 PM

- error node_modules/@apollo/experimental-nextjs-app-support/dist/ssr/RehydrationContext.js (28:0) @ RehydrationContextProvider
- error Error: When using Next SSR, you must use the `NextSSRApolloClient`
import { GetStaticPaths, GetStaticProps, InferGetStaticPropsType } from 'next';
import React from 'react';
import { gql } from '@apollo/client';
import { documentToReactComponents } from '@contentful/rich-text-react-renderer';
import { getClient } from '../libs/apolloServer'; // Adjust the import path as necessary
import { BlogPost as Post } from '../libs/blogTypes';
import { FacebookShareButton, TwitterShareButton } from 'next-share';
import { FaFacebookF, FaTwitter } from "react-icons/fa";

// Type for the object that includes the slug
interface PostSlug {
  slug: string;
}

// GraphQL queries to fetch the slugs for all posts and the details of a post by its slug
const GET_ALL_POSTS_SLUGS = gql`
  query GetAllPostsSlugs {
    pageBlogPostCollection {
      items {
        slug
      }
    }
  }
`;

const GET_POST_BY_SLUG = gql`
  query GetPostBySlug($slug: String!) {
    pageBlogPostCollection(where: { slug: $slug }, limit: 1) {
      items {
        sys {
          id
        }
        title
        slug
        shortDescription
        featuredImage {
          url
          title
        }
        content {
          json
        }
      }
    }
  }
`;

export const getStaticPaths: GetStaticPaths = async () => {
  const apolloClient = getClient();
  const { data } = await apolloClient.query({ query: GET_ALL_POSTS_SLUGS });
  const paths = data.pageBlogPostCollection.items.map(({ slug }: PostSlug) => ({
    params: { slug },
  }));

  return { paths, fallback: 'blocking' };
};

export const getStaticProps: GetStaticProps<{ post?: Post }> = async ({ params }) => {
  if (!params?.slug || typeof params.slug !== 'string') {
    return { notFound: true };
  }
  const apolloClient = getClient();
  const { data } = await apolloClient.query({
    query: GET_POST_BY_SLUG,
    variables: { slug: params.slug },
  });

  const post = data.pageBlogPostCollection.items.length > 0 ? data.pageBlogPostCollection.items[0] : null;

  if (!post) {
    return { notFound: true };
  }

  return { props: { post }, revalidate: 1 };
};

const PostPage: React.FC<InferGetStaticPropsType<typeof getStaticProps>> = ({ post }) => {
  if (!post) {
    return <div>Post not found.</div>;
  }

  const postUrl = `https://yourdomain.com/blog/${post.slug}`;

  return (
    <article>
      <h1>{post.title}</h1>
      {post.shortDescription && <p>{post.shortDescription}</p>}
      {post.featuredImage && (
        <img
          src={post.featuredImage.url}
          alt={post.featuredImage.title || 'Featured image'}
          style={{ width: '100%' }}
        />
      )}
      <div>{documentToReactComponents(post.content.json)}</div>
      <div className="social-share-buttons">
        <FacebookShareButton url={postUrl}>
          <FaFacebookF size={32} />
        </FacebookShareButton>
        <TwitterShareButton url={postUrl}>
          <FaTwitter size={32} />
        </TwitterShareButton>
      </div>
    </article>
  );
};

export default PostPage;

'use client';

import React from 'react';
import { useQuery } from '@apollo/client';
import Link from 'next/link';
import { documentToReactComponents } from '@contentful/rich-text-react-renderer';
import { GET_ALL_POSTS_QUERY } from '../libs/contentful';
import { BlogPost as Post } from '../libs/blogTypes';

const BlogClient = () => {
  const { data, loading, error } = useQuery<{ pageBlogPostCollection: { items: Post[] } }>(GET_ALL_POSTS_QUERY);

  if (loading) return <div className="blog-loading">Loading...</div>;
  if (error) return <div className="blog-error">Error: {error.message}</div>;

  return (
    <div className="blog-container">
      {data?.pageBlogPostCollection.items.map((post) => (
        <article key={post.sys.id} className="blog-post">
          <h2 className="post-title">
            <Link href={`/blog/${post.slug}`}>
              {post.title}
            </Link>
          </h2>
          {post.shortDescription && (
            <p className="post-subtitle">{post.shortDescription}</p>
          )}
          {post.featuredImage && (
            <img
              className="post-image"
              src={post.featuredImage.url}
              alt={post.featuredImage.title || 'Featured image'}
            />
          )}
          <div className="post-excerpt">
            {documentToReactComponents(post.content.json)}
          </div>
        </article>
      ))}
    </div>
  );
};

export default BlogClient;


import React from 'react';
import BlogClient from './BlogClient'; 
import ClientOnly from '@/app/components/ClientOnly'; 

const BlogPage = () => {
  return (
    <ClientOnly>
      <BlogClient />
    </ClientOnly>
  );
};

export default BlogPage;




import React, { Suspense } from 'react';
import { gql } from '@apollo/client';
import { useSuspenseQuery } from "@apollo/experimental-nextjs-app-support/ssr";
import { ApolloWrapper } from '../libs/ApolloWrapper'; // Adjust the import path as necessary
import { BlogPost } from '../libs/blogTypes'; // Adjust the import path as necessary
import { documentToReactComponents } from '@contentful/rich-text-react-renderer';

const BLOG_POSTS_QUERY = gql`
  query GetBlogPosts {
    blogPostsCollection { // Update with actual query and fields
      items {
        sys {
          id
        }
        title
        slug
        shortDescription
        featuredImage {
          url
          title
        }
        content {
          json
        }
      }
    }
  }
`;

const PollPage = () => {
  const { data } = useSuspenseQuery<{ blogPostsCollection: { items: BlogPost[] } }>(BLOG_POSTS_QUERY);
  const blogPosts = data.blogPostsCollection.items;

  return (
    <div>
      {blogPosts.map((post) => (
        <article key={post.sys.id}>
          <h2>{post.title}</h2>
          {post.shortDescription && <p>{post.shortDescription}</p>}
          {post.featuredImage && (
            <img
              src={post.featuredImage.url}
              alt={post.featuredImage.title || 'Featured Image'}
            />
          )}
          <div>{documentToReactComponents(post.content.json)}</div>
        </article>
      ))}
    </div>
  );
};

const PollPageWithSuspense = () => (
  <ApolloWrapper>
    <Suspense fallback={<div>Loading...</div>}>
      <PollPage />
    </Suspense>
  </ApolloWrapper>
);

export default PollPageWithSuspense;

import { ApolloClient, HttpLink, InMemoryCache, ApolloLink } from '@apollo/client';
import { NextSSRInMemoryCache, SSRMultipartLink } from '@apollo/experimental-nextjs-app-support/ssr';

// Configuration for connecting to your GraphQL endpoint
const space = process.env.NEXT_PUBLIC_CONTENTFUL_SPACE_ID;
const accessToken = process.env.NEXT_PUBLIC_CONTENTFUL_ACCESS_TOKEN;
const endpoint = `https://graphql.contentful.com/content/v1/spaces/${space}/environments/master`;

// HTTP Link setup for fetching GraphQL data
const httpLink = new HttpLink({
  uri: endpoint,
  headers: {
    Authorization: `Bearer ${accessToken}`,
  },
});

// Client Components Apollo Client setup with SSR support
export function makeClient() {
  return new ApolloClient({
    cache: new NextSSRInMemoryCache(),
    link: typeof window === "undefined"
      ? ApolloLink.from([new SSRMultipartLink({ stripDefer: true }), httpLink])
      : httpLink,
  });
}

import { ApolloClient, HttpLink, InMemoryCache } from '@apollo/client'; // Import ApolloClient here
import { registerApolloClient } from '@apollo/experimental-nextjs-app-support/rsc';

// Configuration for connecting to your GraphQL endpoint
const space = process.env.NEXT_PUBLIC_CONTENTFUL_SPACE_ID;
const accessToken = process.env.NEXT_PUBLIC_CONTENTFUL_ACCESS_TOKEN;
const endpoint = `https://graphql.contentful.com/content/v1/spaces/${space}/environments/master`;

// HTTP Link setup for fetching GraphQL data
const httpLink = new HttpLink({
  uri: endpoint,
  headers: {
    Authorization: `Bearer ${accessToken}`,
  },
});

// Server Components Apollo Client setup
export const { getClient } = registerApolloClient(() => new ApolloClient({ // ApolloClient is now correctly imported
  cache: new InMemoryCache(),
  link: httpLink,
}));

'use client';
import React from 'react';
import { ApolloNextAppProvider } from '@apollo/experimental-nextjs-app-support/ssr';
import { makeClient } from './apolloClient'; // Adjust the import path as necessary

export function ApolloWrapper({ children }: React.PropsWithChildren<{}>): JSX.Element {
  return (
    <ApolloNextAppProvider makeClient={makeClient}>
      {children}
    </ApolloNextAppProvider>
  );
}



import { ApolloClient, InMemoryCache, HttpLink, gql } from '@apollo/client';
import { BlogPost as Post } from './blogTypes'; 

const space = process.env.NEXT_PUBLIC_CONTENTFUL_SPACE_ID;
const accessToken = process.env.NEXT_PUBLIC_CONTENTFUL_ACCESS_TOKEN;
const client = new ApolloClient({
  link: new HttpLink({
    uri: `https://graphql.contentful.com/content/v1/spaces/${space}`,
    headers: {
      Authorization: `Bearer ${accessToken}`,
    },
  }),
  cache: new InMemoryCache(),
});

// GraphQL queries
export const GET_ALL_POSTS_QUERY = gql`
  query GetAllPosts {
    pageBlogPostCollection {
      items {
        sys {
          id
        }
        title
        slug
        shortDescription
        featuredImage {
          url
          title
          description
        }
        content {
          json
        }
      }
    }
  }
`;

export const GET_POST_BY_SLUG_QUERY = gql`
  query GetPostBySlug($slug: String!) {
    pageBlogPostCollection(where: { slug: $slug }, limit: 1) {
      items {
        sys {
          id
        }
        title
        slug
        shortDescription
        featuredImage {
          url
          title
          description
        }
        content {
          json
        }
      }
    }
  }
`;

// Fetch all blog posts
export async function fetchEntries(): Promise<Post[]> {
  const { data } = await client.query<{ pageBlogPostCollection: { items: Post[] } }>({ query: GET_ALL_POSTS_QUERY });
  return data.pageBlogPostCollection.items;
}

// Fetch a single post by slug
export async function fetchSingleEntry(slug: string): Promise<Post | null> {
  const { data } = await client.query<{ pageBlogPostCollection: { items: Post[] } }>({
    query: GET_POST_BY_SLUG_QUERY,
    variables: { slug },
  });
  return data.pageBlogPostCollection.items.length ? data.pageBlogPostCollection.items[0] : null;
}

import { gql } from '@apollo/client';
import { getClient } from './apolloServer'; // Expects a server-side Apollo Client setup
import { makeClient } from './apolloClient'; // Expects a client-side Apollo Client setup

// Interfaces for typing the responses from Contentful's GraphQL API
interface Sys {
  id: string;
}

interface BlogPost {
  sys: Sys;
  title: string;
  slug: string;
  content: string; // Adjust according to your actual content model
}

interface EntryCollectionResponse {
  entryCollection: {
    items: BlogPost[];
  };
}

interface SingleEntryResponse {
  blogPost: BlogPost;
}

const GET_ENTRIES_QUERY = gql`
  query GetEntries($contentType: String!) {
    entryCollection(where: { contentType: $contentType }) {
      items {
        sys {
          id
        }
        ... on BlogPost {
          title
          slug
          content
        }
      }
    }
  }
`;

const GET_SINGLE_ENTRY_QUERY = gql`
  query GetSingleEntry($entryId: String!) {
    blogPost(id: $entryId) {
      sys {
        id
      }
      title
      slug
      content
    }
  }
`;

// Function to dynamically select the Apollo Client based on execution context
function useApolloClient() {
  // This function decides whether to use the server or client instance
  // of Apollo Client based on the environment.
  return typeof window === 'undefined' ? getClient : makeClient;
}

// Fetch multiple entries by content type
export async function fetchEntries(contentType: string): Promise<BlogPost[]> {
  const client = useApolloClient();
  const { data } = await client().query<EntryCollectionResponse>({
    query: GET_ENTRIES_QUERY,
    variables: { contentType },
  });

  return data.entryCollection.items;
}

// Fetch a single entry by entry ID
export async function fetchSingleEntry(entryId: string): Promise<BlogPost | null> {
  const client = useApolloClient();
  const { data } = await client().query<SingleEntryResponse>({
    query: GET_SINGLE_ENTRY_QUERY,
    variables: { entryId },
  });

  return data.blogPost;
}

I also imported the Apollo Wrapper into my layout and wrapped it around all children components as shown here:

return (
    <html lang="en">
      <body className={font.className}>
      <ApolloWrapper>

        <ClientOnly>
          <ToasterProvider />
          <LoginModal />
          <RegisterModal />
          <SearchModal />
          <RentModal />
          <ConfirmModal />
          <WelcomeModal />
          <DialogModal />
          <DeleteDialogModal />
          <ProfileProvider>
          <ProfileInfoModal />
          </ProfileProvider>
          <Navbar currentUser={currentUser} />
          <ProfileProvider>
          <ProfileModal userId={currentUser?.id} email={currentUser?.email} />
          </ProfileProvider>
        </ClientOnly>

        <div className="flex flex-col min-h-screen">
        <div className="flex-grow pb-20 pt-28">
        <GoogleTagManager id="GTM-PFV4NM5Z" />
          {children}
          <Analytics />
        </div>
        <Footer />
      </div>
      </ApolloWrapper>

      </body>
    </html>
  )
}

from apollo-client.

MarvinTchio avatar MarvinTchio commented on May 25, 2024

Given the Client Components Setup with SSR Support using ApolloClient directly was causing the error because for SSR scenarios, NextSSRApolloClient should be used instead, as indicated by the error messages, I updated the following files and now it works:


'use client';
import React from 'react';
import { ApolloProvider } from '@apollo/client';
import { makeClient } from './apolloClient';

// Explicitly type the props for the component, including typing children as React.ReactNode
interface ApolloWrapperProps {
  children: React.ReactNode;
}

const ApolloWrapper: React.FC<ApolloWrapperProps> = ({ children }) => {
  const client = makeClient();
  return <ApolloProvider client={client}>{children}</ApolloProvider>;
};

export default ApolloWrapper;

'use client';
import React from 'react';
import { ApolloProvider } from '@apollo/client';
import { makeClient } from './apolloClient';

// Explicitly type the props for the component, including typing children as React.ReactNode
interface ApolloWrapperProps {
  children: React.ReactNode;
}

const ApolloWrapper: React.FC<ApolloWrapperProps> = ({ children }) => {
  const client = makeClient();
  return <ApolloProvider client={client}>{children}</ApolloProvider>;
};

export default ApolloWrapper;

Don't see the immediate benefits I was expecting from implementing GraphQL but its been quite something implementing this. I just hope it improves the fetching of my blog content as promised.

from apollo-client.

phryneas avatar phryneas commented on May 25, 2024

I'm very sorry you have to go through all this - unfortunately, at this time it's no fun using Next.js with a third-party fetching library, since Next.js runs your code

  • in a React Server Component build run
  • in a SSR run (use client)
  • in the browser (use client)

and all of those need slightly different setup.

Unfortunately, there is not much we can do about that added complexity :/

Given the Client Components Setup with SSR Support using ApolloClient directly was causing the error because for SSR scenarios, NextSSRApolloClient should be used instead, as indicated by the error messages,

I get that it looks like it is working for you now, but this will execute the same queries once during the SSR run and then again in the browser - is there a reason why you are not using the NextSSRApolloClient as asked by that error message?

I know that the setup is no fun since you have to set up for three environments, but there is really no way around it :/

from apollo-client.

MarvinTchio avatar MarvinTchio commented on May 25, 2024

I forgot to mention this, the main issue with respect to the NextSSRApolloClient issue was that it needed to be distinguished between the client and server side of the apolloClient when in the browser so I needed to ensure that when the ApolloClient got called from fetchContentful.ts it was checked first. The following code displays the separation of the apolloClient.ts into two components (apolloClient.ts and apolloServer.ts) that would run separately and Called when needed by Contentful.

import { HttpLink, InMemoryCache } from '@apollo/client';
import { ApolloLink } from '@apollo/client';
import { NextSSRApolloClient, SSRMultipartLink } from '@apollo/experimental-nextjs-app-support/ssr';
import { loadErrorMessages, loadDevMessages } from "@apollo/client/dev";

// Load development-specific error messages
if (process.env.NODE_ENV !== "production") {
  loadDevMessages();
  loadErrorMessages();
}

// Configuration for connecting to your GraphQL endpoint
const space = process.env.NEXT_PUBLIC_CONTENTFUL_SPACE_ID;
const accessToken = process.env.NEXT_PUBLIC_CONTENTFUL_ACCESS_TOKEN;
const endpoint = `https://graphql.contentful.com/content/v1/spaces/${space}/environments/master`;

// HTTP Link setup for fetching GraphQL data
const httpLink = new HttpLink({
  uri: endpoint,
  headers: {
    Authorization: `Bearer ${accessToken}`,
  },
});

// Function to create an Apollo Client instance
export function makeClient() {
  // Adjust to use NextSSRApolloClient for SSR with appropriate caching and link setup
  return new NextSSRApolloClient({
    link: typeof window === "undefined"
      ? ApolloLink.from([new SSRMultipartLink({ stripDefer: true }), httpLink])
      : httpLink,
    cache: new InMemoryCache(),
  });
}

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

// Configuration for connecting to your GraphQL endpoint
const space = process.env.NEXT_PUBLIC_CONTENTFUL_SPACE_ID;
const accessToken = process.env.NEXT_PUBLIC_CONTENTFUL_ACCESS_TOKEN;
const endpoint = `https://graphql.contentful.com/content/v1/spaces/${space}/environments/master`;

// HTTP Link setup for fetching GraphQL data
const httpLink = new HttpLink({
  uri: endpoint,
  headers: {
    Authorization: `Bearer ${accessToken}`,
  },
});

// Server Components Apollo Client setup
export const { getClient } = registerApolloClient(() => new ApolloClient({ 
  cache: new InMemoryCache(),
  link: httpLink,
}));

import { gql } from '@apollo/client';
import { getClient } from './apolloServer'; 
import { makeClient } from './apolloClient';

// Interfaces for typing the responses from Contentful's GraphQL API
interface Sys {
  id: string;
}

interface BlogPost {
  sys: Sys;
  title: string;
  slug: string;
  content: string; // Adjust according to your actual content model
}

interface EntryCollectionResponse {
  entryCollection: {
    items: BlogPost[];
  };
}

interface SingleEntryResponse {
  pageBlogPost: BlogPost;
}

const GET_ENTRIES_QUERY = gql`
query GetEntries {
  pageBlogPostCollection {
    items {
      sys {
        id
      }
      title
      slug
      content {
        json
      }
    }
  }
}
`;

const GET_SINGLE_ENTRY_QUERY = gql`
  query GetSingleEntry($entryId: String!) {
    pageBlogPost(id: $entryId) {
      sys {
        id
      }
      title
      slug
      content {
        json 
      }
    }
  }
`;

function getApolloClient() {
  // If window is undefined, we are on the server, otherwise we are on the client.
  return typeof window === 'undefined' ? getClient() : makeClient();
}

// Fetch multiple entries by content type
export async function fetchEntries(contentType: string): Promise<BlogPost[]> {
  const client = getApolloClient(); // Use the refactored function here.
  const { data } = await client.query<EntryCollectionResponse>({
    query: GET_ENTRIES_QUERY,
    variables: { contentType },
  });

  return data.entryCollection.items;
}

// Fetch a single entry by entry ID
export async function fetchSingleEntry(entryId: string): Promise<BlogPost | null> {
  const client = getApolloClient(); // And here.
  const { data } = await client.query<SingleEntryResponse>({
    query: GET_SINGLE_ENTRY_QUERY,
    variables: { entryId },
  });

  return data.pageBlogPost;
}

from apollo-client.

github-actions avatar github-actions commented on May 25, 2024

Do you have any feedback for the maintainers? Please tell us by taking a one-minute survey. Your responses will help us understand Apollo Client usage and allow us to serve you better.

from apollo-client.

github-actions avatar github-actions commented on May 25, 2024

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
For general questions, we recommend using StackOverflow or our discord server.

from apollo-client.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.