๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
ํ”„๋ก ํŠธ์—”๋“œ(Front-end)/Tools

TanStack Query ์‚ฌ์šฉํ•ด๋ณด๊ธฐ

by ์ฝ”์ž๋Š” ์•Œ๋ฐ”์ƒ 2025. 5. 14.

 

https://ldd6cr-adness.tistory.com/303

 

Tanstack Query๋Š” ๋ญ˜๊นŒ

๋ชฉ์ฐจ1. TanStack Query๋ž€2. ์„ค์น˜ ๋ฐ ๊ธฐ๋ณธ ์„ค์ • 2-1. TanStack ํŒจํ‚ค์ง€ ์„ค์น˜ 2-2. Query Client ์ƒ์„ฑ ๋ฐ Provider ์„ค์ •3. ๋ฐ์ดํ„ฐ ์กฐํšŒ (Fetching)4. ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ (Mutations)5. ์ฟผ๋ฆฌ ๋ฌดํšจํ™” ๋ฐ ๋ฆฌํŒจ์นญ6. ๊ธฐํƒ€ ๊ธฐ๋Šฅ๋“ค7. ํˆด1. TanSt

ldd6cr-adness.tistory.com

 

 

๋ชฉ์ฐจ

1. ์‹ค์Šต ํ”„๋กœ์ ํŠธ ๋‚ด์šฉ

2. ๊ธฐ๋ณธ ์„ค์ •

    2-1. ๊ธฐ๋ณธ ์„ค์น˜

    2-2. ๋ผ์šฐํŒ… ์„ค์ •

    2-3. TanStack Query ๊ธฐ๋ณธ ์„ค์ •

---< ์‹ค์Šต ์‹œ์ž‘ >---

1. useQuery๋กœ ๋ฐ์ดํ„ฐ ์กฐํšŒ(fetching)

2. useMutation์œผ๋กœ ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ

3. ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ฟผ๋ฆฌ ๋ฌดํšจํ™”/๋ฆฌํŒจ์น˜ ๊ตฌํ˜„

4. ๋ฐ์ดํ„ฐ์˜ ์‹ ์„ ๋„์™€ ์บ์‹œ ์œ ์ง€ ์‹œ๊ฐ„ ์„ค์ •

5. React Query Devtools

 

 


0. ์‹ค์Šต ํ”„๋กœ์ ํŠธ ๋‚ด์šฉ

  • ๊ฒŒ์‹œํŒ ๋ทฐ์–ด : ๊ฒŒ์‹œ๊ธ€ ๋ชฉ๋ก์„ ๋ถˆ๋Ÿฌ์˜ค๊ณ , ์ƒ์„ธ ๋‚ด์šฉ์„ ํ™•์ธํ•จ
  • ๊ธฐ์ˆ  ์Šคํƒ
    • React
    • TanStack Query
    • JSONPlaceholder API (/posts, /posts/:id, /posts/:comment)
    • React Router
  • ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ
    • src/
      -- App.tsx
      -- index.tsx
      -- components/
          ใ„ด PostList.tsx
          ใ„ด PostDetail.tsx
          ใ„ด CommentForms
      -- api/
          ใ„ด posts.ts
          ใ„ด comments.ts

2. ๊ธฐ๋ณธ ์„ค์ •

2-1. ๊ธฐ๋ณธ ์„ค์น˜

npm install
npm install @tanstack/react-query react-router-dom

npm ํŒจํ‚ค์ง€๋ฅผ ์„ค์น˜ํ•˜๊ณ , tanstak๊ณผ ํŽ˜์ด์ง€ ์ด๋™์„ ์œ„ํ•œ react-router-dom์„ ์„ค์น˜ํ–ˆ๋‹ค.

 

2-2. ๋ผ์šฐํŒ… ์„ค์ •

import React from 'react';
import {Route, Routes} from 'react-router-dom';
import { PostList } from './components/PostList.tsx';
import { PostDetail } from './components/PostDetail.tsx';

function App() {
  return (
    <div>
      <h1 style={{ color: 'black', textAlign: 'center' }}>๊ฒŒ์‹œํŒ</h1>
      <Routes>
        <Route path="/" element={<PostList />} />
        <Route path="/posts/:id" element={<PostDetail />} />
        </Routes>
    </div>
  );
}

export default App;

์ด ๋ถ€๋ถ„ ํ™”๋ฉด์ด ์•ˆ๋‚˜์™€์„œ ๋ณด๋‹ˆ๊นŒ ์ฒ˜์Œ์—” div๊ฐ€ ์•„๋‹ˆ๋ผ BrowserRouter๋กœ ๊ฐ์‹ธ๊ณ  ์žˆ์—ˆ๋Š”๋ฐ,

index.tsx์—์„œ ์ด๋ฏธ BrowserRouter๋กœ ๊ฐ์‹ธ์„œ ์ด์ค‘์œผ๋กœ ๊ฐ์‹ธ๋ฒ„๋ฆฌ๋Š” ๋ฐ”๋žŒ์— ํ™”๋ฉด์ด ์•ˆ๋‚˜์™”๋˜ ๊ฑฐ์˜€๋‹ค.

** BrowserRouter๋Š” ํ•ญ์ƒ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ตœ์ƒ์œ„์— ์œ„์น˜ํ•˜๊ฒŒ ํ•˜๋ฉฐ, ์—ฌ๋Ÿฌ ๋ฒˆ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋„๋ก ํ•˜์ž~ **

 

2-3. TanStack Query ๊ธฐ๋ณธ ์„ค์ •

// index.tsx

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App.tsx';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { BrowserRouter as Router } from 'react-router-dom';

const queryClient = new QueryClient();
const root = ReactDOM.createRoot(document.getElementById('root'));

root.render(
  <React.StrictMode>
    <QueryClientProvider client={queryClient}>
      <Router>
        <App />
      </Router>
    </QueryClientProvider>
  </React.StrictMode>
);

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ง„์ž…์ ์ธ index.tsx ํŒŒ์ผ์— QueryClient, QueryClientProvider๋ฅผ ์ง€์ •ํ•œ๋‹ค.

QueryClient ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ: TanStack Query๊ฐ€ ์ƒํƒœ, ์บ์‹œ, ๋ฆฌํŒจ์น˜ ๋“ฑ ๋‹ค์–‘ํ•œ ๊ธฐ๋Šฅ์„ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•จ

QueryClientProvider ์ปดํฌ๋„ŒํŠธ: React ์ปดํฌ๋„ŒํŠธ ํŠธ๋ฆฌ ์ „์ฒด์—์„œ TanStack Query ํ›…์ด ์ž‘๋™ํ•˜๋„๋ก QueryClient ์ „๋‹ฌ

 

๋ฐ์ดํ„ฐ ๊ด€๋ฆฌ๋ฅผ ์ „์—ญ์—์„œ ํ•˜๊ธฐ ์œ„ํ•ด QueryClientProvider๋ฅผ ์ตœ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ(App) ์™ธ๋ถ€์— ๋‘”๋‹ค.

 

 


๊ธฐ๋ณธ์ ์ธ ๋ถ€๋ถ„๋“ค์„ ์ž‘์„ฑํ–ˆ์œผ๋‹ˆ ์ด์ œ ๋ณธ๊ฒฉ์ ์œผ๋กœ TanStack Query๋ฅผ ์‚ฌ์šฉํ•ด๋ณผ ์‹œ๊ฐ„~!

 


1. useQuery๋กœ ๋ฐ์ดํ„ฐ ์กฐํšŒ(fetching)                                                     

1. API ํ•จ์ˆ˜ ์ •์˜

// api/posts.ts

export const fetchPosts = async () => {
  const response = await fetch('https://jsonplaceholder.typicode.com/posts');
  if (!response.ok) {
    throw new Error('failed to fetch posts');
  }
  return response.json();
}

export const fetchPostById = async (id: number) => {
  const response = await fetch(`https://jsonplaceholder.typicode.com/posts/${id}`);
  if (!response.ok) {
    throw new Error('failed to fetch post by id');
  }
  return response.json();
}

posts์™€ ๊ด€๋ จ๋œ ์š”์ฒญ์„ ์ •์˜ํ•œ ํŒŒ์ผ์ด๋‹ค.

 

fetchPosts : ๋ชจ๋“  ๊ฒŒ์‹œ๊ธ€ ๋ชฉ๋ก์„ ์„œ๋ฒ„์— ์š”์ฒญํ•ด์„œ ๋ฐ›์•„์˜ค๋Š” ํ•จ์ˆ˜

jsonplaceholder ์„œ๋ฒ„์— ์š”์ฒญํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›๊ณ , js ๊ฐ์ฒด๋กœ ๋ณ€ํ™˜ํ•œ๋‹ค.

 

fetchPostById : ํŠน์ • ID๋ฅผ ๊ฐ€์ง„ ๊ฒŒ์‹œ๊ธ€ ํ•˜๋‚˜๋งŒ ์„œ๋ฒ„์— ์š”์ฒญํ•ด์„œ ๋ฐ›์•„์˜ค๋Š” ํ•จ์ˆ˜

์ธ์ž id: number๋ฅผ ํ†ตํ•ด ์ˆซ์ž ํ•˜๋‚˜(=id)๋ฅผ ์ž…๋ ฅ๋ฐ›๋Š”๋‹ค.

 

 

 

2. PostList ์ปดํฌ๋„ŒํŠธ

// components/PostList.tsx

import React from 'react';
import { useQuery } from '@tanstack/react-query';
import { fetchPosts } from "../api/posts.ts";
import { Link } from "react-router-dom";

export function PostList() {
    const { data, isLoading, error } = useQuery({
        queryKey: ['posts'],
        queryFn: fetchPosts,
    });

    if (isLoading) return <p>Loading...</p>;
    if (error instanceof Error) return <p>error: {error.message}</p>;

    return (
        <ul>
            {data.slice(0, 10).map((post: any) => (
                <li key={post.id}>
                    <Link to={`/posts/${post.id}`}>{post.title}</Link>
                </li>
            ))}
        </ul>
    )
}

fetchPosts api ํ•จ์ˆ˜๋กœ ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ๋ฐ›์•„์˜จ ๊ฐ’์„ post ์ œ๋ชฉ 10๊ฐœ๋ฅผ ๋„์šฐ๋Š” ์ปดํฌ๋„ŒํŠธ์ด๋‹ค.

 

useQuery ํ›…์„ ์‚ฌ์šฉํ•˜์—ฌ ์„œ๋ฒ„์— ์š”์ฒญํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ , ์ƒํƒœ๋ฅผ ์ž๋™์œผ๋กœ ๊ด€๋ฆฌํ•œ๋‹ค.

queryKey: ['posts'] => ์ด ์š”์ฒญ์˜ ์ด๋ฆ„ํ‘œ๋กœ, TanStack Query๊ฐ€ 'posts'๋ฅผ ๊ธฐ์–ตํ•ด์„œ ๋‚˜์ค‘์— ๋‹ค์‹œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

queryFn: fetchPosts => ์‹ค์ œ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ํ•จ์ˆ˜๋กœ, ์ •์˜ํ•ด๋‘” fetchPosts๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

 

useQuery ํ›…์ด ๊ธฐ๋ณธ ์ œ๊ณตํ•˜๋Š” ์†์„ฑ์ธ isLoading๊ณผ error ์†์„ฑ๋“ค์„ ์‚ฌ์šฉํ•ด์„œ ํ•ด๋‹น ์ƒํƒœ์ผ ๊ฒฝ์šฐ ๋ณด์—ฌ์ค„ ์ปจํ…์ธ ๋ฅผ ์ž‘์„ฑํ•œ๋‹ค.

 

 

3. PostDetail ์ปดํฌ๋„ŒํŠธ

import {useParams} from 'react-router-dom';
import {useQuery} from '@tanstack/react-query';
import { fetchPostById } from '../api/posts.ts';
import React from 'react';

export function PostDetail() {
    const {id} = useParams<{ id: string }>();
    const postId = Number(id);

    const { data, isLoading, error } = useQuery({
        queryKey: ['posts', id],
        queryFn: () => fetchPostById(postId!),
        enabled: !!id, // id๊ฐ€ ์žˆ์„ ๋•Œ๋งŒ ์ฟผ๋ฆฌ ์‹คํ–‰
    });

    if (isLoading) return <p>Loading...</p>;
    if (error instanceof Error) return <p>error: {error.message}</p>;

    return (
        <div>
            <h2>{data.title}</h2>
            <p>{data.body}</p>
        </div>
    )
}

PostList ์ปดํฌ๋„ŒํŠธ์™€ ๋‹ค๋ฅด๊ฒŒ key๋กœ id๋„ ๊ฐ™์ด ์‚ฌ์šฉํ•œ๋‹ค.

๋˜ํ•œ enabled ์†์„ฑ์„ ์‚ฌ์šฉํ•˜์—ฌ id๊ฐ€ ์กด์žฌํ•  ๋•Œ๋งŒ ์ฟผ๋ฆฌ๋ฅผ ์‹คํ–‰ํ•˜๋„๋ก ํ–ˆ๋‹ค.

 

๊ฒฐ๊ณผ ํ™”๋ฉด



 

 


2. useMutation์œผ๋กœ ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ                                                     

1. API ํ•จ์ˆ˜ ์ •์˜ : ๋Œ“๊ธ€ ์ž‘์„ฑ

// api/comments.ts

export const postComment = async (comment: {
  postId: number;
  name: string;
  body: string;
}) => {
  const response = await fetch(
    "https://jsonplaceholder.typicode.com/comments",
    {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify(comment),
    }
  );

  if (!response.ok) {
    throw new Error("Failed to post comment");
  }

  return response.json();
};

- ์™ธ๋ถ€ API์— ๋Œ“๊ธ€ POST๋ฅผ ์š”์ฒญํ•˜๊ณ  ์ €์žฅํ•˜๋Š” ํ•จ์ˆ˜๋‹ค.

jsonplaceholder ์ƒ˜ํ”Œ API๋Š” (comment: {postId: number; name: string; body: string }) ๊ตฌ์กฐ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›๋Š”๋‹ค.

ํ•ด๋‹น ํ˜•์‹์€ jsonplaceholder ์›น์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

 

๊ฐ ์†์„ฑ๋“ค์€ ์•„๋ž˜์™€ ๊ฐ™์€ ๋ฐ์ดํ„ฐ๋ฅผ ๋‚˜ํƒ€๋‚ธ๋‹ค.

  • postId => ์–ด๋–ค ๊ธ€(post)์— ๋Œ€ํ•œ ๋Œ“๊ธ€์ธ์ง€
  • name => ๋Œ“๊ธ€ ์ž‘์„ฑ์ž์˜ ์ด๋ฆ„
  • body => ๋Œ“๊ธ€ ๋‚ด์šฉ

method: "POST"

: ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋‚ธ๋‹ค. ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜ฌ ๋•Œ๋Š” "GET"์„ ์‚ฌ์šฉํ•œ๋‹ค.

 

headers; { "Content-Type: "application/json" }

: JSON ํ˜•์‹์œผ๋กœ ์š”์ฒญํ•จ์„ ์„œ๋ฒ„์— ์•Œ๋ ค์ค€๋‹ค.

 

body: JSON.stringify(comment)

์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“  comment ๊ฐ์ฒด(json ํ˜•ํƒœ)๋ฅผ ๋ฌธ์ž๋กœ ๋ณ€ํ™˜

 

 

 

2. ๋Œ“๊ธ€ ์ž‘์„ฑ ํผ ์ปดํฌ๋„ŒํŠธ ์ƒ์„ฑ

// components/CommentForm.tsx

import React, { useState } from "react";
import { useMutation } from "@tanstack/react-query";
import { postComment } from "../api/comments";

interface CommentFormProps {
  postId: number;
}

export function CommentForm({ postId }: CommentFormProps) {
  const [name, setName] = useState("");
  const [body, setBody] = useState("");

  const mutation = useMutation({
    mutationFn: postComment,
    onSuccess: (data) => {
      alert("๋Œ“๊ธ€์ด ๋“ฑ๋ก๋˜์—ˆ์Šต๋‹ˆ๋‹ค๐Ÿ‘");
      console.log(data); // ์‘๋‹ต ํ™•์ธ
      setName("");
      setBody("");
    },
    onError: (error: Error) => {
      alert(`error: ${error.message}`);
    },
  });

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    mutation.mutate({ postId, name, body });
  };

  return (
    <form onSubmit={handleSubmit}>
      <h3>add Comment</h3>
      <input
        type="text"
        placeholder="name"
        value={name}
        onChange={(e) => setName(e.target.value)}
        required
      />
      <br />
      <textarea
        placeholder="add your comment"
        value={body}
        onChange={(e) => setBody(e.target.value)}
        required
      />
      <br />
      <button type="submit" disabled={mutation.isPending}>
        write
      </button>
    </form>
  );
}

 

 

 

3. PostDetail์— ๋Œ“๊ธ€ ์ž‘์„ฑ ํผ ์ถ”๊ฐ€

import { useParams } from "react-router-dom";
import { useQuery } from "@tanstack/react-query";
import { fetchPostById } from "../api/posts.ts";
import React from "react";
import { CommentForm } from "./CommentForm.tsx";

export function PostDetail() {
  const { id } = useParams<{ id: string }>();
  const postId = Number(id);

  const { data, isLoading, error } = useQuery({
    queryKey: ["posts", id],
    queryFn: () => fetchPostById(postId!),
    enabled: !!id, // id๊ฐ€ ์žˆ์„ ๋•Œ๋งŒ ์ฟผ๋ฆฌ ์‹คํ–‰
  });

  if (isLoading) return <p>Loading...</p>;
  if (error instanceof Error) return <p>error: {error.message}</p>;

  return (
    <div>
      <h2>{data.title}</h2>
      <p>{data.body}</p>
      <CommentForm postId={postId} /> {/*๋Œ“๊ธ€ ์ถ”๊ฐ€ ํผ */}
    </div>
  );
}

 

 

๊ฒฐ๊ณผ ํ™”๋ฉด


3. ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ฟผ๋ฆฌ ๋ฌดํšจํ™”/๋ฆฌํŒจ์นญ ๊ตฌํ˜„                                  

1. api ํ•จ์ˆ˜ createPost ์ •์˜

// api/posts.ts
// ...
export const createPost = async (newPost: { title: string; body: string; userId: number }) => {
  const response = await fetch('https://jsonplaceholder.typicode.com/posts', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(newPost),
  });

  if(!response.ok) {
    throw new Error('failed to create post');
  }
  return response.json();
};

 

 

2. PostList.tsx์—์„œ queryClient.invalidateQueries๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ ๋ฌดํšจํ™”+์ž๋™๋ฆฌํŒจ์นญ

// components/PostList.tsx
import React from 'react';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';	// ๊ฒŒ์‹œ๊ธ€ ๋ชฉ๋ก ์ˆ˜์ •์„ ์œ„ํ•ด ํ›… import
import { fetchPosts, createPost } from "../api/posts.ts";	// ํ•„์š”ํ•œ api ํ•จ์ˆ˜ createPost import
import { Link } from "react-router-dom";


export function PostList() {
	// queryClient ํ›… ์‚ฌ์šฉ์„ ์œ„ํ•ด queryClient ์ •์˜
    const queryClient = useQueryClient();

    // ๊ฒŒ์‹œ๊ธ€ ๋ชฉ๋ก ๊ฐ€์ ธ์˜ค๊ธฐ
    const { data, isLoading, error } = useQuery({
        queryKey: ['posts'],
        queryFn: fetchPosts,
    });

    // ๊ฒŒ์‹œ๊ธ€ ์ถ”๊ฐ€ mutation
    const mutation = useMutation({
        mutationFn: createPost,
        onSuccess: () => {
            // ๊ฒŒ์‹œ๊ธ€ ์ถ”๊ฐ€ํ›„ posts ์ฟผ๋ฆฌ ๋ฌดํšจํ™” ๋ฐ (์ž๋™)๋ฆฌํŒจ์น˜
            queryClient.invalidateQueries({queryKey:['posts']});
            alert('Post added successfully!๐Ÿ‘');
        },
    });

    const handleAddPost = () => {
        const newPost = {
            title: 'New Post',
            body: 'This is a new post.',
            userId: 1,
        };
        mutation.mutate(newPost);
    };

    if (isLoading) return <p>Loading...</p>;
    if (error instanceof Error) return <p>error: {error.message}</p>;

    return (
        <div>
            <h1>Post List</h1>
            <button onClick={handleAddPost}>Add Post</button>
        <ul>
            {data.slice(0, 10).map((post: any) => (
                <li key={post.id}>
                    <Link to={`/posts/${post.id}`}>{post.title}</Link>
                </li>
            ))}
        </ul>
        </div>
    )
}

 

๊ฒฐ๊ณผ ํ™”๋ฉด

 

 


4. ๋ฐ์ดํ„ฐ์˜ ์‹ ์„ ๋„์™€ ์บ์‹œ ์œ ์ง€ ์‹œ๊ฐ„ ์„ค์ •                                

1. staleTime, cacheTime ์˜ต์…˜์œผ๋กœ ๋ฐ์ดํ„ฐ์˜ ์‹ ์„ ๋„ ๋ฐ ์บ์‹œ ์œ ์ง€ ์‹œ๊ฐ„์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค

์ฒซ ๋งˆ์šดํŠธ ์‹œ, ๋กœ๊ทธ ํ™•์ธ(์š”์ฒญ ๋ฐœ์ƒ)์ด ๋œ๋‹ค.

  • staleTime
    • 1000*5(5์ดˆ) ๋™์•ˆ์€ ๋ฐ์ดํ„ฐ๊ฐ€ ์‹ ์„ ํ•œ ๊ฒƒ์œผ๋กœ ๊ฐ„์ฃผ๋˜์–ด, ํŽ˜์ด์ง€๋ฅผ ๋ฒ—์–ด๋‚ฌ๋‹ค๊ฐ€ 5์ดˆ ์•ˆ์— ๋“ค์–ด์˜ค๋ฉด ์š”์ฒญ์ด ์—†๋‹ค.
    • staleTime์„ ์„ค์ •ํ•˜์ง€ ์•Š์„๊ฒฝ์šฐ, ํŽ˜์ด์ง€๋ฅผ ๋ฒ—์–ด๋‚ฌ๋‹ค ๋Œ์•„์˜ฌ ๋•Œ๋งˆ๋‹ค ํ•ญ์ƒ ์š”์ฒญ์ด ๋ฐœ์ƒํ•œ๋‹ค(fetchPosts ํ˜ธ์ถœ)
  • cacheTime
    • ์บ์‹œ๋œ ์ฟผ๋ฆฌ ๋ฐ์ดํ„ฐ๊ฐ€ 15์ดˆ๋งˆ๋‹ค ์ œ๊ฑฐ๋œ๋‹ค.
    • ์บ์‹œ๋Š” ์ฟผ๋ฆฌ๊ฐ€ ์ข…๋ฃŒ๋  ๋•Œ ๋ฐ”๋กœ ์ œ๊ฑฐ๋˜๋‚˜, ์œ„ ์ฝ”๋“œ์—์„œ๋Š” 15์ดˆ๋™์•ˆ์€ ์บ์‹œ๋œ ๋ฐ์ดํ„ฐ๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ์— ์œ ์ง€๋œ๋‹ค.
    • React Query Devtools๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์บ์‹œ ์ƒํƒœ๋ฅผ ๋ˆˆ์œผ๋กœ ํ™•์ธํ•  ์ˆ˜ ์žˆ์œผ๋‚˜, Network ํƒญ์—์„œ๋Š” ์บ์‹œ์˜ ์ œ๊ฑฐ ์—ฌ๋ถ€๋ฅผ ์•Œ ์ˆ˜ ์—†๋‹ค.

 


5. React Query Devtools                               

1. ์„ค์น˜

npm install @tanstack/react-query-devtools

2. Devtool ๋ Œ๋”๋ง

// index.tsx ( QueryClientProvider ํ•˜์œ„)

import { ReactQueryDevtools } from '@tanstack/react-query-devtools';

function App() {
	return (
    	<QueryClientProvider client={queryClient}>
        	{/* application components */}
            <ReactQueryDevtools initialIsOpen={false} />
        </QueryClientProvider>
    );
}

 

๊ฒฐ๊ณผ ํ™”๋ฉด

 

ํ™”๋ฉด ๊ตฌ์„์— ๋ณด์ด๋Š” TanStack Query DevTool ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํ™”๋ฉด์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

์ƒ‰๊น”๋ณ„๋กœ ์•„๋ž˜์™€ ๊ฐ™์€ ์ƒํƒœ๋ฅผ ๋‚˜ํƒ€๋‚ธ๋‹ค.

Fresh(์ดˆ๋ก), Fetching(ํŒŒ๋ž‘), Paused(๋ณด๋ผ), Stale(๋…ธ๋ž‘), Inactive(ํšŒ์ƒ‰) 

์ฆ‰, ํ™”๋ฉด์„ ์ฒซ ๋งˆ์šดํŠธ, ํ˜น์€ 5์ดˆ ์•ˆ์— ๋‹ค์‹œ ๋Œ์•„์™”์„ ๋•Œ๋Š” posts ์š”์ฒญ์ด ์ดˆ๋ก์ƒ‰์ด๋‚˜, 5์ดˆ ํ›„์—๋Š” ๋…ธ๋ž€์ƒ‰์ด ๋œ๋‹ค.

 

์ฒซ ํ™”๋ฉด์—์„œ ๋‹ค๋ฅธ ํ™”๋ฉด์œผ๋กœ ๋„˜์–ด๊ฐ„ ํ›„ 15์ดˆ๊ฐ€ ์ง€๋‚˜๋ฉด(์˜ˆ๋กœ PostLists์—์„œ PostDetails ํ™”๋ฉด์œผ๋กœ)

์œ„ ์‚ฌ์ง„๊ณผ ๊ฐ™์ด Inactive ์š”์ฒญ(PostLists์—์„œ์˜ ์š”์ฒญ)์ด ์‚ญ์ œ = cache ์‚ญ์ œ๊ฐ€ ๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

 

 

 

๐Ÿฅบ๋ฌธ์ œ ์ƒ๊ฒผ๋˜ ๋ถ€๋ถ„

: ๊ณ„์† cacheTime์—์„œ ์—๋Ÿฌ๊ฐ€ ๋‚˜๊ธธ๋ž˜ ์ฐพ์•„๋ดค๋”๋‹ˆ ์—…๋ฐ์ดํŠธ ํ•ด์„œ ์ด์ œ cacheTime์€ ์•ˆ์“ฐ๊ณ  gcTime (garbage collection)์„ ์“ด๋‹ค๊ณ  ํ•œ๋‹ค. ์‚ฝ์งˆ...ใ…Žใ…Ž

cacheTime์œผ๋กœ ์ž‘์„ฑํ–ˆ์„ ๋•Œ๋Š” ์บ์‹œ ์‚ญ์ œ๊ฐ€ ์ œ๋Œ€๋กœ ์•ˆ๋๋Š”๋ฐ gcTime์œผ๋กœ ๋ณ€๊ฒฝํ•˜๋ฉด ์ž˜ ๋œ๋‹ค.

'ํ”„๋ก ํŠธ์—”๋“œ(Front-end) > Tools' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

axios๋Š” ๋ญ˜๊นŒ  (1) 2025.05.22
Zustand ์‚ฌ์šฉํ•ด๋ณด๊ธฐ  (0) 2025.05.15
Tanstack Query๋Š” ๋ญ˜๊นŒ  (0) 2025.05.08
Zustand๋Š” ๋ญ˜๊นŒ  (0) 2025.04.04
Next.js๋Š” ๋ญ˜๊นŒ  (0) 2025.03.20