Replies: 3 comments
-
My guess is that the first fetch happens in the You should be able to access the data in Page like this, without using that custom hook: |
Beta Was this translation helpful? Give feedback.
-
By the way, I noticed that you (and many others) export the queryClient at the top level and import it later. Now, I'm also quite new to RR7 and trying to figure out the best way to work with it, and I noticed this in the tanstack query docs:
Although this is in the next.js section it doesn't explicitly mention that it's next.js only, It would be great if someone would confirm that it's fine to do in Remix/RR7. On a similar note I'm playing around with something similar, but in addition I'm trying to SSR on the first page load, hydrate the queryClient and use it for making further requests. It seems to work and this is how it looks so far: export default function App() {
const [queryClient] = useState(
() =>
new QueryClient({
defaultOptions: {
queries: {
staleTime: 1000 * 60 * 60,
refetchOnWindowFocus: false,
},
},
}),
)
return (
<QueryClientProvider client={queryClient}>
<NuqsAdapter>
<Outlet />
</NuqsAdapter>
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
);
} export async function loader({ params }: Route.LoaderArgs) {
const queryClient = new QueryClient()
await queryClient.prefetchQuery({
queryKey: ['books', params.authorId],
queryFn: () => getBooksByAuthor(params.authorId),
})
return { dehydratedState: dehydrate(queryClient) }
}
let isInitialRequest = true
export async function clientLoader({ serverLoader }: Route.ClientLoaderArgs) {
if (isInitialRequest) {
isInitialRequest = false;
return await serverLoader();
}
return { dehydratedState: undefined }
}
clientLoader.hydrate = true as const
export default function BooksRoute({ params, loaderData }: Route.ComponentProps) {
const { authorId } = params
const { dehydratedState } = loaderData
return (
<HydrationBoundary state={dehydratedState}>
<Books authorId={authorId} />
</HydrationBoundary>
);
}
function Books({ authorId }: { authorId: string }) {
const { data } = useQuery({
queryKey: ['books', authorId],
queryFn: () => getBooksByAuthor(authorId),
})
return (
... First time using RR7 so definitely wondering how others go about it. |
Beta Was this translation helpful? Give feedback.
-
Hi @nordboerg, thanks for your detailed answers. We found a fix by using loaderData as initalData for useQuery in the Component which stopped duplicate fetching the data successful.
But still this feels not ok. After we hit the next issue with using ErrorBoundary from react-error-boundary with an esm import issue (due to a failure by react-router vite plugin) we stopped use react-router 7 and switched to TanStack Router. We are currently developing a new template for our internal React Stack and it looks like RR7 as framework with vite is not mature enough yet. We do not want SSR and RR7s origin of Remix could be one of the reasons for this issues. |
Beta Was this translation helpful? Give feedback.
-
I found a perfect example to use React Router pre V7 with Tanstack React-Query.
https://tkdodo.eu/blog/react-query-meets-react-router
I adapted the example to work with React Router 7:
root.tsx (excerpt):
use-graphql.ts:
page.tsx (excerpt):
Now opening that route leads to load the data twice, because the queryClient is different in clientLoader and the useGraphQL somehow.
use-graphql.ts:15 Fetching graphQLQuery (2) ['countries', 'none']
use-graphql.ts:16 Fetch finished loading: POST "https://countries.trevorblades.com/". (triggered via Loader)
overview.tsx:17 Loaded 250 countries
use-graphql.ts:34 Fetching useGraphQL (2) ['countries', 'none']
use-graphql.ts:35 Fetch finished loading: POST "https://countries.trevorblades.com/". (triggered via useGraphQL)
It should just deliver the already loaded data.
How to get the correct queryClient in the loader?
Thanks.
Beta Was this translation helpful? Give feedback.
All reactions