Tanstack Query๋Š” ๋ญ˜๊นŒ

2025. 5. 8. 00:25ใ†Front-end/Tools

๋ฐ˜์‘ํ˜•

๋ชฉ์ฐจ

1. TanStack Query๋ž€

2. ์„ค์น˜ ๋ฐ ๊ธฐ๋ณธ ์„ค์ •

    2-1. TanStack ํŒจํ‚ค์ง€ ์„ค์น˜

    2-2. Query Client ์ƒ์„ฑ ๋ฐ Provider ์„ค์ •

3. ๋ฐ์ดํ„ฐ ์กฐํšŒ (Fetching)

4. ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ (Mutations)

5. ์ฟผ๋ฆฌ ๋ฌดํšจํ™” ๋ฐ ๋ฆฌํŒจ์นญ

6. ๊ธฐํƒ€ ๊ธฐ๋Šฅ๋“ค

7. ํˆด


1. TanStack Query๋ž€

์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ, ์บ์‹ฑ, ์ œ์–ด ๋“ฑ ๋ฐ์ดํ„ฐ์˜ ํšจ์œจ์ ์ธ ๊ด€๋ฆฌ๋ฅผ ๋•๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ด๋‹ค.

https://tanstack.com/query/latest

 

TanStack Query

Powerful asynchronous state management, server-state utilities and data fetching. Fetch, cache, update, and wrangle all forms of async data in your TS/JS, React, Vue, Solid, Svelte & Angular applications all without touching any "global state"

tanstack.com

 

๋Œ€ํ‘œ์ ์ธ ๊ธฐ๋Šฅ

  • ๋ฐ์ดํ„ฐ ํŒจ์นญ ๋ฐ ์บ์‹ฑ : API๋กœ๋ถ€ํ„ฐ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ  ์บ์‹œ์— ์ €์žฅํ•˜์—ฌ, ๋ถˆํ•„์š”ํ•œ ๋„คํŠธ์›Œํฌ ์š”์ฒญ ๋ฐฉ์ง€
  • ์ž๋™ ๋ฆฌํŒจ์นญ : ๋ฐ์ดํ„ฐ์˜ ์‹ ์„ ๋„๋ฅผ ์œ ์ง€ํ•˜๊ธฐ ์œ„ํ•ด, ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ์ž๋™์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐฑ์‹ 
  • ๋ฌดํ•œ ์Šคํฌ๋กค, ํŽ˜์ด์ง€๋„ค์ด์…˜ ๋“ฑ์˜ ์„ฑ๋Šฅ ์ตœ์ ํ™”
  • ์—๋Ÿฌ ์ฒ˜๋ฆฌ ๋ฐ ์žฌ์‹œ๋„ : ๋„คํŠธ์›Œํฌ ์˜ค๋ฅ˜ ๋ฐœ์ƒ ์‹œ ์ž๋™์œผ๋กœ ์žฌ์‹œ๋„, ์—๋Ÿฌ ์ƒํƒœ๋ฅผ ์‰ฝ๊ฒŒ ๊ด€๋ฆฌ
  • ์ฟผ๋ฆฌ ๋ฌดํšจํ™” : ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ ํ›„ ๊ด€๋ จ๋œ ์ฟผ๋ฆฌ๋ฅผ ๋ฌดํšจํ™”ํ•˜์—ฌ ์ตœ์‹  ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ˜์˜

 


2. ์„ค์น˜ ๋ฐ ๊ธฐ๋ณธ ์„ค์ •

1. Tanstack Query ํŒจํ‚ค์ง€ ์„ค์น˜

npm i @tanstack/react-query

 

 

2. QueryClient ์ƒ์„ฑ ๋ฐ Provider ์„ค์ •

TanStack Query๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด QueryClient๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ๋ฃจํŠธ์— QueryClientProvider๋ฅผ ์„ค์ •ํ•œ๋‹ค.

import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
const queryClient = new QueryClient();

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

 

 


3. ๋ฐ์ดํ„ฐ ์กฐํšŒ (Fetching)

useQuery hook์„ ์‚ฌ์šฉํ•˜์—ฌ fetchingํ•œ๋‹ค.

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

function Posts() {
    const { data, isLoading, error } = useQuery({
        queryKey: ['posts'],
        queryFn: async () => {
            const response = await fetch('https://jsonplaceholder.typicode.com/posts');
            if (!response.ok) {
                throw new Error('Network response was not ok');
            }
            return response.json();
        },
    });

    if (isLoading) retun <div> loading... </div>
    if (error) return <div> error:{error.msg}</div>

    return (
        <ul>
            {data.map((post) => (
                <li key={post.id}>{post.title}</li>
            ))}
        </ul>
    );
}

** queryKey : ์บ์‹œ ์‹๋ณ„์ž

** queryFn : ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๋น„๋™๊ธฐ ํ•จ์ˆ˜

 

 


4. ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ (Mutations)

useMutation hook์„ ์‚ฌ์šฉํ•˜์—ฌ ์„œ๋ฒ„์— ๋ฐ์ดํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ์ˆ˜์ •ํ•œ๋‹ค.

import {useMutation, useQueryClient } from '@tanstack/reac-query';

function AddPost() {
	const queryClient = useQueryClient();
    
    const mutation = useMutation({
    	mutationFn: async (newPost) => {
        	const response = await fetch('https://jsonplaceholder.typicode.com/posts',
                method: 'POST',
                body: JSON.stringify(newPost),
                headers: { 'Content-Type': 'application/json'},
        	});
        	if(!response.ok) {
        		throw new Error('Network response was not ok');
        	}
        	return response.json();
    	},
        onSuccess: () => {
            // 'posts' query๋ฅผ ๋ฌดํšจํ™”ํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ์ƒˆ๋กœ ๊ณ ์นจ
           queryClient.invalidateQueries({ queryKey: ['posts']});
        },
    });

    const handleAddPost = () => {
        mutation.mutate({ title: 'new post', body: 'contents', userId: 1 });
    };

    return <button onClick={handleAddPost}> add post</button>;
}

onSuccess ์ฝœ๋ฐฑ์—์„œ ๊ด€๋ จ ์ฟผ๋ฆฌ๋ฅผ ๋ฌดํšจํ™”ํ•˜์—ฌ ์ตœ์‹  ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค.

 

 


5. ์ฟผ๋ฆฌ ๋ฌดํšจํ™” ๋ฐ ๋ฆฌํŒจ์นญ

๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ ํ›„, ํ˜น์€ ํŠน์ • ์กฐ๊ฑด์— ๋”ฐ๋ผ ํŠน์ • ์ฟผ๋ฆฌ๋ฅผ ๋ฌดํšจํ™”ํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ์ƒˆ๋กœ ๊ณ ์นจํ•  ์ˆ˜ ์žˆ๋‹ค.

queryClient.invalidateQueries({queryKey: ['posts'] });

 

 


6. ๊ธฐํƒ€ ๊ธฐ๋Šฅ๋“ค

enabled ์˜ต์…˜์„ ์‚ฌ์šฉํ•ด์„œ ์ฟผ๋ฆฌ ์‹คํ–‰ ์—ฌ๋ถ€(ํ™œ์„ฑํ™” ์กฐ๊ฑด)์„ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๋‹ค.

useQuery({
    queryKey: ['user', userId],
    queryFn: fetchUser,
    enabled: !!userId,	//userId๊ฐ€ ์žˆ์„ ๋•Œ๋งŒ ์‹คํ–‰
});

 

select ์˜ต์…˜์„ ์‚ฌ์šฉํ•ด์„œ ์ฟผ๋ฆฌ ๊ฒฐ๊ณผ๋ฅผ ์„ ํƒํ•˜๊ณ  ๋ณ€ํ™˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

useQuery({
	queryKey: ['posts'],
    queryFn: fetchPosts,
    select: (data) => data.slice(0, 10),	//์ƒ์œ„ 10๊ฐœ ํฌ์ŠคํŠธ ์„ ํƒ
});

 

staleTime, cacheTime ์˜ต์…˜์„ ์‚ฌ์šฉํ•ด์„œ ๋ฐ์ดํ„ฐ์˜ ์‹ ์„ ๋„์™€ ์บ์‹œ ์œ ์ง€ ์‹œ๊ฐ„์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

useQuery({
	queryKey: ['posts'],
    queryFn: fetchPosts,
    staleTime: 1000 * 60 * 5,	//5๋ถ„ ๋™์•ˆ freshํ•œ ๋ฐ์ดํ„ฐ๋กœ ๊ฐ„์ฃผ
    cacheTime: 1000 * 60 * 10,	//10๋ถ„ ๋™์•ˆ ์บ์‹œ ์œ ์ง€
});

 

 


7. ํˆด

React Query Devtools๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ฟผ๋ฆฌ ์ƒํƒœ๋ฅผ ์‹œ๊ฐ์ ์œผ๋กœ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

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

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

 

 

 

 

 

์˜ˆ์ œ ์‹ค์Šต

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

 

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

์ง€๋‚œ ๋ฒˆ์— TanStack Query์— ๋Œ€ํ•ด ์ญ‰ ํ›‘์–ด๋ดค์œผ๋‹ˆJSONPlaceholder๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๋ฏธ๋‹ˆ ํ”„๋กœ์ ํŠธ ์˜ˆ์ œ๋กœ Tanstack Query๋ฅผ ํ™œ์šฉํ•ด๋ณด์ž. ์‹ค์Šต ํ”„๋กœ์ ํŠธ ๋‚ด์šฉ๊ฒŒ์‹œํŒ ๋ทฐ์–ด : ๊ฒŒ์‹œ๊ธ€ ๋ชฉ๋ก์„ ๋ถˆ๋Ÿฌ์˜ค๊ณ , ์ƒ์„ธ ๋‚ด์šฉ์„ ํ™•

ldd6cr-adness.tistory.com

 

๋ฐ˜์‘ํ˜•