리액트 라우트 프레임워크+탠스택 쿼리

김현준·2026년 4월 16일

리액트 이모저모

목록 보기
31/31

✅ 목표

  • loader에서 데이터 미리 가져오기 (prefetch)
  • 컴포넌트에서는 useQuery로 캐시 사용

👉 로딩 없이 바로 렌더되는 구조


✅ 1. QueryClient

// queryClient.ts
import { QueryClient } from "@tanstack/react-query";

export const queryClient = new QueryClient();

✅ 2. API 함수

// api/fetchPosts.ts
export async function fetchPosts() {
  const res = await fetch("https://jsonplaceholder.typicode.com/posts");

  if (!res.ok) throw new Error("API 에러");

  return res.json();
}

✅ 3. loader + 페이지 (핵심)

// routes/posts.tsx
import { queryClient } from "../queryClient";
import { fetchPosts } from "../api/fetchPosts";
import { useQuery } from "@tanstack/react-query";

// ✅ loader: 페이지 들어가기 전에 실행
export async function loader() {
  await queryClient.ensureQueryData({
    queryKey: ["posts"],
    queryFn: fetchPosts,
  });

  return null;
}

// ✅ 컴포넌트
export default function PostsPage() {
  const { data, isLoading } = useQuery({
    queryKey: ["posts"],
    queryFn: fetchPosts,
  });

  if (isLoading) return <div>로딩중...</div>;

  return (
    <div>
      <h1>게시글 리스트</h1>
      {data.map((post: any) => (
        <div key={post.id}>{post.title}</div>
      ))}
    </div>
  );
}

✅ 4. 라우트 등록 (Framework Mode)

// routes.ts
import { route } from "@react-router/dev/routes";

export default [
  route("/", "routes/posts.tsx"),
];

✅ 5. root 설정 (중요)

// root.tsx
import {
  QueryClientProvider,
  HydrationBoundary,
} from "@tanstack/react-query";
import { queryClient } from "./queryClient";

export default function Root({ children }: { children: React.ReactNode }) {
  return (
    <QueryClientProvider client={queryClient}>
      <HydrationBoundary>
        {children}
      </HydrationBoundary>
    </QueryClientProvider>
  );
}

🔥 실행 흐름 (이게 핵심 이해 포인트)

1. "/" 라우트 진입
2. loader 실행
3. queryClient에 posts 데이터 저장됨
4. 컴포넌트 렌더
5. useQuery → 캐시 데이터 즉시 사용

👉 그래서
isLoading 거의 안 뜨고 바로 데이터 보인다


💡 실무 확장 (검색 + 페이지네이션)

// loader
export async function loader({ request }: any) {
  const url = new URL(request.url);
  const page = url.searchParams.get("page") ?? "1";

  await queryClient.ensureQueryData({
    queryKey: ["posts", page],
    queryFn: () => fetchPosts(page),
  });

  return null;
}
// component
const { data } = useQuery({
  queryKey: ["posts", page],
  queryFn: () => fetchPosts(page),
});

⚡ 핵심 정리

loader

  • 페이지 들어가기 전에 실행
  • 데이터 미리 가져오기

TanStack Query

  • 캐싱
  • 상태 관리
  • refetch

👉 둘을 합치면

빠른 초기 렌더 + 강력한 캐싱

🧠 한 줄 정리

👉 loader = “미리 가져오기”
👉 useQuery = “재사용 + 관리”

profile
기록하자

0개의 댓글