ReactQuery를 사용할 땐 QueryClientProvider를 사용하는데, Astro환경에서는 어떻게 사용해보면 좋을까?

Provider

아주 간단한 방식은 기존 방식대로 App 컴포넌트에 QueryClientProvider를 씌우는 것이다.

<body>
	<App client:lony />
</body>

하지만 Astro Islands을 활용할 수 없다는 치명적인 단점이 있다.

전역 상태

nanostores를 통해서 queryClient를 전역 상태화를 하면 된다.

// src/stores/query.ts
 
import { QueryClient } from "@tanstack/react-query";
import { atom } from "nanostores";
 
export const queryClient = atom(new QueryClient());
// src/components/Example.tsx
 
import { useStore } from "@nanostores/react";
import { useQuery } from "@tanstack/react-query";
import { queryClient } from "../stores/query";
 
export default function Example() {
  const client = useStore(queryClient);
  const { data } = useQuery({
      queryKey: ["example"],
      queryFn: async () => "Hello, world!",
  }, client);
 
  return (
    <div>
      <h1>{data}</h1>
    </div>
  );
}

SSR을 할 수 없어, client:only를 해야한다.

<Example client:only="react" />

고도화할 수 있는 방법을 찾아 보자.

nanostores

import { QueryClient, QueryObserver } from '@tanstack/query-core';
import { atom, onMount } from 'nanostores';
 
export const queryClient = atom(new QueryClient());
 
export const posts = atom<object | null>(null);
 
onMount(posts, () => {
  const observer = new QueryObserver<object>(queryClient.get(), {
    queryKey: ['posts'],
    queryFn: () => fetch(`https://dummyjson.com/posts`).then((res) => res.json()),
  });
  const unsubscribe = observer.subscribe(({ data }) => data && posts.set(data));
 
  return async () => {
    unsubscribe();
  };
});

https://github.com/TanStack/query/discussions/5152#discussioncomment-5399784

import { QueryClient, QueryObserver, type QueryObserverResult } from '@tanstack/query-core';
import { atom, onMount } from 'nanostores';
 
export const queryClient = atom(new QueryClient());
 
export const postsQuery = atom<QueryObserverResult<object> | null>(null);
onMount(postsQuery, () => {
  const observer = new QueryObserver<object>(queryClient.get(), {
    queryKey: ['posts'],
    queryFn: () => fetch(`https://dummyjson.com/posts`).then((res) => res.json()),
  });
 
  return observer.subscribe((query) => {
    postsQuery.set(query);
  });
});
 
export const postQuery = atom<QueryObserverResult<object> | null>(null);
let unsubscribePostQuery = () => {};
 
export function fetchPostQuery(postId: string) {
  unsubscribePostQuery();
 
  const observer = new QueryObserver<object>(queryClient.get(), {
    queryKey: ['posts', postId],
    queryFn: () => fetch(`https://dummyjson.com/posts/${postId}`).then((res) => res.json()),
  });
 
  unsubscribePostQuery = observer.subscribe((query) => {
    postQuery.set(query);
  });
}

참고

https://hounie.me/writings/how-to-use-react-query-with-astro/