React Query는 서버 상태를 관리하는 강력한 라이브러리야.
TypeScript와 함께 사용할 때는 query/mutation의 입력, 응답 타입을 정확하게 설정하는 것이 핵심이야.
useQuery
에 제네릭 타입 적용import { useQuery } from '@tanstack/react-query';
type User = {
id: number;
name: string;
};
const fetchUser = async (): Promise<User> => {
const res = await fetch('/api/user');
return res.json();
};
const UserComponent = () => {
const { data, isLoading, error } = useQuery<User>({
queryKey: ['user'],
queryFn: fetchUser,
});
if (isLoading) return <p>로딩 중...</p>;
if (error) return <p>에러 발생</p>;
return <h2>{data?.name}</h2>;
};
✅ useQuery<User>() 처럼 응답 타입을 제네릭으로 지정하면 data의 타입이 정확하게 추론돼.
queryKey
는 항상 고유하게 설정해야 캐시가 구분돼.
useMutation
의 입력/응답 타입import { useMutation } from '@tanstack/react-query';
type NewTodo = {
title: string;
};
type CreatedTodo = {
id: number;
title: string;
};
const createTodo = async (todo: NewTodo): Promise<CreatedTodo> => {
const res = await fetch('/api/todos', {
method: 'POST',
body: JSON.stringify(todo),
headers: { 'Content-Type': 'application/json' },
});
return res.json();
};
const TodoAdder = () => {
const mutation = useMutation<CreatedTodo, Error, NewTodo>({
mutationFn: createTodo,
onSuccess: (data) => {
console.log('생성된 TODO:', data.id);
},
});
return (
<button
onClick={() => mutation.mutate({ title: '새 작업 추가하기' })}
>
추가
</button>
);
};
✅ useMutation<응답, 에러, 입력> 순서로 타입 지정해.
mutate()
함수에 전달하는 데이터도 자동 완성돼서 사용이 훨씬 편해져.
const usePost = (id: number) => {
return useQuery<Post>({
queryKey: ['post', id],
queryFn: async () => {
const res = await fetch(`/api/posts/${id}`);
return res.json();
},
});
};
✅ queryKey에 ID나 파라미터 값을 포함하면 캐싱이 ID 단위로 작동돼.
쿼리 키에 따라 데이터가 캐싱되고 자동으로 갱신돼.
const useTodos = () => {
return useQuery<Todo[]>({
queryKey: ['todos'],
queryFn: async () => {
const res = await fetch('/api/todos');
return res.json();
},
});
};
const TodoList = () => {
const { data: todos = [], isLoading } = useTodos();
return isLoading ? (
<p>로딩 중...</p>
) : (
<ul>
{todos.map((todo) => (
<li key={todo.id}>{todo.title}</li>
))}
</ul>
);
};
✅ data: todos = [] 처럼 기본값을 설정하면 undefined 체크 없이 안전하게 사용할 수 있어.