Closed jnovak-SM2Dev closed 3 weeks ago
You would get that error when trying to import registerApolloClient
(or a file that, around a hundred corners, imports from a file that imports registerApolloClient
) from a "use client"
file.
Are you sure you are only referencing getClient
from Server Components?
Do you maybe use barrel-exports like index.js
files that combine Server Component and Client Component exports in a single file?
For this specific instance i'm trying to use it in the auth.ts
Credentials
call from auth.js
. I believe this is a server file, but it's a bit confusing what is and isn't at this point. What is the proper way to make a call in a client component without state?
I'm not sure what you mean by "without state", but in Client Components you'd use the hooks.
What hooks? The docs don't mention anything about the client side hooks for some reason.
I assume it's just useQuery
and calls from the old version of apollo? How can I await a client call in an async function?
To better explain, in an older project with normal apollo and the pages router I had to do something like this:
const client = initializeApollo();
const { data } = await client.mutate({
mutation: loginQuery,
variables: {
input: {
provider: "local",
identifier: email,
password: password,
},
});
How would I handle something like this with this version?
I made an example project showing the error. Notes are in the Readme.
https://github.com/jnovak-SM2Dev/next-apollo-sample
Note: I am talking with the Auth.js guys in discord as well. Not sure who's end the issue is on.
Had the same issue on Next.js, here's what I found out.
Some of the hooks are documented here: https://www.apollographql.com/docs/react/data/queries
But if you don't need useLazyQuery() or useMutation() to update your React components afterwards, there's also useApolloClient(). Use it in the component body and pass the result to the function that needs to perform some async action:
function MyComponent() {
const client = useApolloClient();
...
const handleMyCallback = (inputs) => {
client.mutation({ ...
}
Not sure it it's necessary but I also made sure that component only run client-side using this technique
I have to admit that I'm still struggling a bit about what exactly @jnovak-SM2Dev wants to do here.
I'll lay out our recommendations:
registerApolloClient
+ getClient
.ApolloWrapper
and useSuspenseQuery
or useBackgroundQuery
. Only those two will run during SSR and transport their data over, useQuery
is browser-only (will just be loading in SSR).ApolloWrapper
that way.I do not know how auth.js
plays into all of that, as I'm not familiar with them.
Generally, apart from the Cookies/Auth part, you'd just write your code like you always would with the modern useSuspenseQuery
/useBackgroundQuery
hooks and this library takes care about any SSR data transport for you automatically.
I am using a login mutation to get a JWT token. I then use auth.js
to manage the session. The issue is for some reason using getClient
in the credentials provider (which I was told is server side) causes the error about registerApolloClient
.
Looking at your repository, you are doing so in a Route Handler?
Those don't really need any additional treatment as long as you create a new Apollo Client instance every time your route handler is called.
registerApolloClient
is currently only targeting "React Server Component" - in Next.js there are a lot of different "Server" things (React Server Components, Server Side Rendering, Server Actions, Middleware, Route Handlers), not all of them need to go through registerApolloClient
.
We will add support for more of those as soon as we identify use cases that give users additional benefit, but right now just calling const client = makeClient()
in your route handler without registerApolloClient
is good enough and we can't provide any benefit on top.
@phryneas That makes sense. When I try makeClient()
it throws different errors though.
Error:
TypeError: _apollo_experimental_nextjs_app_support_ssr__WEBPACK_IMPORTED_MODULE_0__.NextSSRInMemoryCache is not a constructor
Is this how i'm supposed to setup makeClient()
?
import { ApolloLink, HttpLink } from "@apollo/client";
import {
NextSSRApolloClient,
NextSSRInMemoryCache,
SSRMultipartLink,
} from "@apollo/experimental-nextjs-app-support/ssr";
export function makeClient() {
const httpLink = new HttpLink({
// this needs to be an absolute url, as relative urls cannot be used in SSR
uri: process.env.API_URL,
// 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" },
// you can override the default `fetchOptions` on a per query basis
// via the `context` property on the options passed as a second argument
// to an Apollo Client data fetching hook, e.g.:
// const { data } = useSuspenseQuery(MY_QUERY, { context: { fetchOptions: { cache: "force-cache" }}});
});
return new NextSSRApolloClient({
// use the `NextSSRInMemoryCache`, not the normal `InMemoryCache`
cache: new NextSSRInMemoryCache(),
link:
typeof window === "undefined"
? ApolloLink.from([
// in a SSR environment, if you use multipart features like
// @defer, you need to decide how to handle these.
// This strips all interfaces with a `@defer` directive from your queries.
new SSRMultipartLink({
stripDefer: true,
}),
httpLink,
])
: httpLink,
});
}
Sorry, it's confusing with all the client, server, makeClient, getClient, bop-it, twist-it, turn-it, style stuff I need to do. At the end of the day I just want to login the user and get a token lol.
If I add use client
to makeClient
, it throws another error as well.
TypeError: (0 , _makeClient__WEBPACK_IMPORTED_MODULE_2__.makeClient) is not a function
Yeah, unfortunately Next.js has about 6 different scenarios in which your JavaScript code can run.
With makeClient
I mean that you just create a function that creates an ApolloClient
instance of your, not the prop passed into ApolloNextAppProvider
.
You shouldn't be using NextSSRInMemoryCache
or NextSSRApolloClient
outside of Client Components. (React Components in files with "use client"
or imported by such files).
Generally, your route handler has nothing to do with React at all (Next runs it without React!), so you don't need to pull this package into it, as this package is meant for interaction with React Server Components and React Client Components, not any non-React functionality.
@phryneas That worked!! Thanks!!
Yeah all this server/client nonsense is a bit annoying. I wish there was an easy way to make it so the end user just needs to call getClient
anywhere and it just works.
Here's the code I used in case anyone else needs it.
import { ApolloClient, HttpLink, InMemoryCache } from "@apollo/client";
export function makeClient() {
const httpLink = new HttpLink({
uri: process.env.API_URL,
fetchOptions: { cache: "no-store" },
});
return new ApolloClient({
cache: new InMemoryCache(),
link: httpLink,
});
}
And in the auth.ts
or wherever you need it you can just do:
const client = makeClient();
const { data } = await client.mutate({
mutation: loginMutation,
variables: {
loginInput: {
email: credentials.email as string,
password: credentials.password as string,
},
},
});
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.
When I try to use
getClient().query
I get the following error:Any thoughts on what could cause this issue?
The full call i'm using:
Next: 14.1.3 @apollo/client: 3.9.11 @apollo/experimental-nextjs-app-support: 0.10.0