Closed iewher closed 1 month ago
You have to mark the file using useQuery
as a Client Component file with "use client"
at the top of the file.
Then it won't run in React Server Components, but only during SSR and in the Browser. Since useQuery
does not run anything in SSR, your query would only happen in the browser.
I moved the client into a separate component
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({
// this needs to be an absolute url, as relative urls cannot be used in SSR
uri: "/api/v2/query",
// you can disable result caching here if you want to
// (this does not work if you are rendering your page with `export const dynamic = "force-static"`)
// fetchOptions: { cache: "no-store" },
}),
});
});
then I try to call it like this:
const { data: category } = await getClient().query({ query: GET_CATEGORY_QUERY })
console.log(category)
my apollo provider
"use client"
import { ApolloProvider } from "@apollo/client"
import { ReactNode } from "react"
import { getClient } from "./client"
export const ApolloContext = ({ children }: { children: ReactNode }) => {
const client = getClient()
return <ApolloProvider client={client}>{children}</ApolloProvider>
}
error:
'server-only' cannot be imported from a Client Component module. It should only be used from a Server Component.
The error was caused by importing '@apollo/experimental-nextjs-app-support/dist/rsc/index.js' in './contexts/apollo/client.ts'.
why do I get an error if I export getClient not from a client component
Oh, sorry, I misread your comment as "I don't want to do it on the server".
You can do so in React Server Components, but that means using getClient.query()
, not the useQuery
hook.
Oh... now you're just mixing things up.
Please take a step back and stop doing what you do right now :)
"use client" import { ApolloProvider } from "@apollo/client" import { ReactNode } from "react" import { getClient } from "./client" export const ApolloContext = ({ children }: { children: ReactNode }) => { const client = getClient() return <ApolloProvider client={client}>{children}</ApolloProvider> }
This is not the way to use Apollo Client in Next.js.
You can use Apollo Client in two distinct ways in Next.js
registerApolloClient
-> getClient().query(...)
- this approach does not use hooks documented hereApolloNextAppProvider
and preferrably useSuspenseQuery
instead of useQuery
(useQuery
will not run in SSR). documented here This does not call the getClient
from your Server Components!That said, loking at your code snippets:
getClient
is something to only call in React Server Components. You're using a RSC api in a Client Component hereApolloProvider
is something you should never directly use in Next.jsThank you for sending links to documentation You wrote that I can use the Apollo client in two different ways, I did that, now my code looks like this
apolloContext.ts
"use client";
import { ApolloLink, HttpLink } from "@apollo/client";
import {
ApolloNextAppProvider,
NextSSRInMemoryCache,
NextSSRApolloClient,
SSRMultipartLink,
} from "@apollo/experimental-nextjs-app-support/ssr";
function makeClient() {
const httpLink = new HttpLink({
uri: "/api/v2/query",
fetchOptions: { cache: "no-store" },
});
return new NextSSRApolloClient({
cache: new NextSSRInMemoryCache(),
link:
typeof window === "undefined"
? ApolloLink.from([
new SSRMultipartLink({
stripDefer: true,
}),
httpLink,
])
: httpLink,
});
}
export function ApolloContext({ children }: React.PropsWithChildren) {
return (
<ApolloNextAppProvider makeClient={makeClient}>
{children}
</ApolloNextAppProvider>
);
}
and
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: "/api/v2/query/",
}),
});
});
In the case of useQuery everything works fine, but in the case of getClient it doesn’t, here is the code and error
import { getClient } from "contexts/apollo/client"
export default async function CategoryPage({ params }: PageProps) {
const { data } = await getClient().query({ query: GET_CATEGORIES_QUERY })
console.log(data)
}
Unhandled Runtime Error
Error: Failed to parse URL from /api/v2/query
Why does one option work and the other not? Thank you for all your efforts
When you're on a server, you cannot make a request to an url like /api/v2/query
. The server doesn't know what that relative path would be relative to - there is no URL bar.
Is it http://localhost:8000/api/v2/query
? Is it https://example.com/api/v2/query
?
You need to specify a full URL on the server.
You need to specify a full URL on the server.
In this case, why does useQuery work and return data normally?
Hey @iewher 👋
Please see the comment above which explains why this works with useQuery
during SSR (emphasis mine).
Using
ApolloNextAppProvider
and preferrablyuseSuspenseQuery
instead ofuseQuery
(useQuery
will not run in SSR)
Thank you for your efforts, I figured it out, the issue can be closed
Awesome to hear! Have a great day 🙂
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.
Hi, I apologize in advance if I distracted you This is my first time having to render a request on the server side. I'm trying to get data from graphql, but I can't do it on the server side, which is very important for me, because metadata is used.
request:
usage:
my ApolloNextProvider :
my layout:
I don't understand why it gives me this error How can I tell if I'm trying to call a client function from the server? Got the information from your readme file Help pls