Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proper way to use urql into nextjs app router? #3686

Open
siamahnaf opened this issue Oct 3, 2024 Discussed in #3684 · 3 comments
Open

Proper way to use urql into nextjs app router? #3686

siamahnaf opened this issue Oct 3, 2024 Discussed in #3684 · 3 comments

Comments

@siamahnaf
Copy link

siamahnaf commented Oct 3, 2024

From this documentations-

https://commerce.nearform.com/open-source/urql/docs/advanced/server-side-rendering/#nextjs

I am clear about data fetching in Server Components and Client Components. But I want to know is there any way to fetch data in Server components and will be cached for all its nested client components. It is my first questions-

I see, using useQuery hook from @urql/next in client component, without wrapping Suspense boundary almost behave as ssr data fetch. I don't get any flashed or flicker, it just fetch data from ssr and show smothly. But in my previous project I see that, in production, some page which has multiple useQuery in a client component, causing continuous data fetch and hanging the sites. After some research and reading docs carefully I see I need to wrap with Suspense. After wrapping with Suspense continuous data fetching and page hang was solved, but there is a loading screen.

Without wrapping Suspense using useQuery do not suspend query after getting initial response even when I use suspense: true on client creations.

See the video-

Screen.Recording.2024-10-03.at.11.38.57.PM.mp4

In the video, I just use useQuery from @urql/next package.

image

In this screenshot, all the component insideFragment is client component, And I use useQuery for fetching data like SSR data fetch without loading, flashing. It works perfectly, it fetching data from SSR. But issue is continuous fetching, which one I show on video.

If I wrap with Suspense boundary like below image-

image

Continuous data fetch getting solved, but I see flashed while fetching data, for getting rid of this flashed, I need to a give a loading component on fallback. On the other hand, I didn't find any documentation for fetching data on Server Component and then cached it for client components.

I try to find if there is any useSuspenseQuery, I do not find it.

If anyone know the mechanism about this, please explain?

Again, if there is any way to fetch data on Server component and cached to it all nested client components. Because I don't want to show a loading screen in my page, using Suspense we need to do that. Tanstack query already has the options for caching data to client component from server component.

I create client like following way-

"use client"
import { useMemo, ReactNode } from "react";
import { UrqlProvider, ssrExchange, cacheExchange, fetchExchange, createClient } from "@urql/next";
import { getCookie } from "cookies-next";

//Interface
interface Props {
    children: ReactNode;
    cookie: string;
}

const Provider = ({ children, cookie }: Props) => {
    //Cookie
    const token = getCookie("NAOWSbL1sKQ30aq9", { path: "/" });

    //Client
    const [client, ssr] = useMemo(() => {
        const ssr = ssrExchange({
            isClient: typeof window !== "undefined"
        });
        const client = createClient({
            url: process.env.NEXT_PUBLIC_API_URL as string,
            exchanges: [cacheExchange, ssr, fetchExchange],
            suspense: true,
            fetchOptions: {
                headers: {
                    authorization: `Bearer ${cookie ?? token}`
                }
            }
        })
        return [client, ssr]
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, []);

    return (
        <UrqlProvider client={client} ssr={ssr}>
            {children}
        </UrqlProvider>
    );
};

export default Provider;

Here is my example code.

https://github.com/siamahnaf/nextjs-middleware-warning

@siamahnaf siamahnaf changed the title Urql with nextjs app router? Proper way to use urql into nextjs app router? Oct 3, 2024
@JoviDeCroock
Copy link
Collaborator

JoviDeCroock commented Nov 1, 2024

Your main questions seems to be, you want to fetch data inside of your sever-component and carry over the cache to your client component. This is possible, as seen in this example, you can fetch data on your server-component - now to use this on the client you would have to add this data to the ssrExchange which would look a bit like:

export default async function Home() {
  const result = await getClient().query(PokemonsQuery, {});
  return (
    <main>
      <h1>This is rendered as part of an RSC</h1>
      <MyClientComponent result={result} />
    </main>
  );
}

And in your client-component

export default function MyClientComponent({ result }) {
  useMemo(() => {
        ssrExchange.restoreData({
          [result.operation.key]: {
            extensions: JSON.stringify(result.extensions),
            data: JSON.stringify(result.data),
            error: result.error,
          },
     })
  }, [result])

  const result = useQuery({ query: PokemonsQuery, variables: {} });

That is a way to rehydrate the cache of your urql component on the client.

We could look at doing something similar to tanstack/query where we have a component that does essentially that but that's what it comes down to 😅

@siamahnaf
Copy link
Author

But why directly using useQuery from '@urql/next' without Suspense Boundary is not suspending the query execution after first load. It continued placing the request. I show you on the video?

@JoviDeCroock
Copy link
Collaborator

JoviDeCroock commented Nov 1, 2024

That's a next thing I reckon - suspense throws a Promise they probably catch it. The continuous data fetch is basically Next catching the Promise and doing a full rerender... hence why you need Suspense boundaries when you are using suspense 😅 hence why we have that docs comment

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants