apollographql / apollo-client-nextjs

Apollo Client support for the Next.js App Router
https://www.npmjs.com/package/@apollo/experimental-nextjs-app-support
MIT License
358 stars 25 forks source link

Infinite loading with `useQuery` #48

Closed MarkLauer closed 10 months ago

MarkLauer commented 10 months ago

Hello, I've been trying to use the package for SSR, but if I call useQuery in a client component, the request is not executed on the server side and there's infinite loading in the browser (transported data is always{ data: undefined, loading: true }). Also the browser doesn't execute the query too (however, I guess it is meant to be this way because the client considers the request already done on the server).

I've created a demo based on polls-demo example from this repository.

Also I want to say thank you to the contributors of this package, it is so convenient to have a first-class support of RSC/SSR for Apollo+Next.js combo.

quocanhbk commented 10 months ago

I've encountered the same issue. It even keeps rendering infinitely and eventually freezes my browser. I set up the project based from this article

Here is my home page code:

// app/page.tsx
"use client";

import { gql } from "@apollo/client";
import { useQuery } from "@apollo/experimental-nextjs-app-support/ssr";

const query = gql`
  query Acts {
    acts {
      id
      title
    }
  }
`;

export default async function Home() {
  const { data, loading, called } = useQuery(query);

  console.log({ data, loading, called });

  return (
    <div>
      <h1>Client Component</h1>
      <p>Loading: {loading ? "True" : "False"}</p>
      <p>Data:</p>
      <pre>{JSON.stringify(data, null, 2)}</pre>
    </div>
  );
}

Here is the repo to reproduce the issue: https://github.com/quocanhbk/nextjs-app-dir-test

Here is the result of infinite render:

image
phryneas commented 10 months ago

So, here's the thing about useQuery: it won't start a request during SSR, because that would require it to suspend and substatially change the way that useQuery is expected to work from a developer perspective. If you want to do the request during SSR, you'd need to use useSuspenseQuery or useBackgroundQuery.
The ssr-package useQuery is just a modified version that will latch onto values that might exist in the server's Apollo Client (probably because you ran useBackgroundQuery in a parant component) and makes sure that hydrates correctly on the client.

All that said, on the client it should make a request and then eventually come back with a result. Irritatingly enough, your repo just goes into an infinite render loop for me - even all Apollo Client parts commented out there, so I'm not sure what's going on there.

patrick91 commented 10 months ago

@phryneas looks like importing gql triggers the re-rendering:

https://github.com/apollographql/apollo-client-nextjs/assets/667029/0ddd1f0f-baf9-4255-bf18-de4dfdf408e4

phryneas commented 10 months ago

I'm pretty sure that this is an error that was introduced with v0.3 - in the meantime, please try using v0.2 - it will (as explained above) not make a request on the server, but it will not prevent the request on the client.

quocanhbk commented 10 months ago

I downgraded to the following version:

 "@apollo/client": "3.8.0-beta.3",
 "@apollo/experimental-nextjs-app-support": "0.2.1",

Although it managed to get the data, it still causes infinite render loop image

phryneas commented 10 months ago

Yeah I still see that, even just using useQuery from @apollo/client instead. I am investigating, but this is a weird one 🤔

phryneas commented 10 months ago

I got your bug. Please remove the async from your Home client component. Client component cannot be async, and it makes Nextjs run against the wall. That, together with #49 should solve everything. I'll put out a release.

quocanhbk commented 10 months ago

It did work! Thanks a lot! I wish Next.js could handle this better though

phryneas commented 10 months ago

Also, I just released v0.3.2 for you - but generally you probably want to prefer useSuspenseQuery over useQuery :)

MarkLauer commented 10 months ago

@phryneas Thank you, it's fixed. But for some reason a component with useSuspenseQuery is not SSR'ed with data, the Suspense fallback is rendered in the initial HTML, can you please check into that? Or is it better to create a new issue for that?

phryneas commented 10 months ago

Yeah, please open a new issue for that. I am off for today, but I will check tomorrow.