Open davit-b opened 1 year ago
Can anyone help here?
I never tried, but I don't think atoms created by jotai-tanstack-query should be hydrated on the Jotai end.
This is my setup:
providers.tsx
"use client";
import React from "react";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
import { ReactQueryStreamedHydration } from "@tanstack/react-query-next-experimental";
import { Provider } from "jotai";
import HydrateQueryClientAtom from "~/components/HydrateQueryClientAtom"
export default function Providers({ children }: { children: React.ReactNode }) {
const [queryClient] = React.useState(() => new QueryClient());
return (
<QueryClientProvider client={queryClient}>
<ReactQueryStreamedHydration>
<Provider>
<HydrateQueryClientAtom queryClient={queryClient}>
{children}
</HydrateQueryClientAtom>
</Provider>
</ReactQueryStreamedHydration>
<ReactQueryDevtools initialIsOpen={true} />
</QueryClientProvider>
);
}
Providers wrap my entire app in the root layout.tsx
.
HydrateQueryClientAtom.tsx
"use client";
import type { QueryClient } from "@tanstack/query-core";
import { queryClientAtom } from "jotai-tanstack-query";
import { useHydrateAtoms } from "jotai/utils";
const HydrateQueryClientAtom = ({ children, queryClient }: { children: React.ReactNode; queryClient: QueryClient }) => {
useHydrateAtoms([[queryClientAtom, queryClient]]);
return children;
};
export default HydrateQueryClientAtom;
And then in any page wrapped by this layout I can go something like:
import { dehydrate } from "@tanstack/query-core";
import { HydrationBoundary } from "@tanstack/react-query";
async function preFetchSomeData() {
const queryClient = getQueryClient();
await queryClient.prefetchQuery({ queryKey: ["key", params], queryFn: dataQueryFunction });
const dehydratedState = dehydrate(queryClient);
return dehydratedState
}
export default async function SomePage() {
const dehydratedState = await preFetchSomeData()
return (
<HydrationBoundary state={dehydratedState}>
// ...
</HydrationBoundary>
);
}
I hope that answers your questions.
@estubmo Extremely helpful.
Similar to my Tanstack-only setup right now.
export default async function HydratedApp() {
const data = await getDataServerSide() // server-side data fetching function
const queryClient = getQueryClient()
queryClient.setQueryData(['QUERY_KEY'], data)
const dehydratedState = dehydrate(queryClient)
return (
<Hydrate state={dehydratedState}>
<App /> // The `use client` wrapped SPA in inside of <App />
</Hydrate>
)
}
// Inside a component deep in the tree.
const { data: userData } = useQuery({
queryKey: ['QUERY_KEY'],
queryFn: getDataClientSide //client-side datafetching function
})
BUT with Tanstack-only I have to access data client-side using Tanstack's convention, and my React components are subscribed using Tanstack's hooks — and I can't use the magic of Jotai for deriving atoms or anything off that data.
Before I ask any followups, I'm going to experiment with this setup and report my findings. Thank you!
You're very welcome. I updated the example, as it was missing an essential part, calling queryClient.prefetch()
.
I think that might be a more suitable API than setQueryData.
https://tanstack.com/query/v4/docs/react/reference/QueryClient#queryclientprefetchquery
I've created a React SPA using Next13 appDir, Jotai, and Tanstack.
Question: What order do I hydrate in?
Option A:
useHydrateAtoms
initialData
// app/page.tsx [SERVER] export default async function Page() { const data = getUser()
return (
) }
// /components/HydratorComponent 'use client' import React from 'react'
function HydratorComponent({initialDataSentFromServer}) { useHydrateAtoms([[dataAtom, initialDataSentFromServer]]) return (
) }
TL;DR: SERVER (fetch) -> CLIENT (as props) -> useHydrateAtom (the queryAtom)
I'm a beginner and I really like Jotai. Would love to figure out the best practice for this.