📌 탄스택 쿼리
서버로부터 데이터 가져오기, 데이터 캐싱, 캐시 제어 등 데이터를 쉽고 효율적으로 관리할 수 있는 라이브러리.
React Query라는 이름으로 시작했지만, v4부터 Vue나 Svelte 등의 다른 프레임워크에서도 활용할 수 있도록 기능이 확장되며 TanStack Query라는 이름으로 변경되었다.
1. 탄스택 쿼리의 특징
- 데이터 가져오기 및 캐싱
- 동일 요청의 중복 제거
- 신선한 데이터 유지
- 무한 스크롤, 페이지네이션 등의 성능 최적화
- 네트워크 재연결, 요청 실패 등의 자동 갱신
- 옵션에 쿼리 키(queryKey) 필수!!
2. useQuery
가장 기본적인 쿼리 훅, 컴포넌트에서 데이터를 가져올 때 사용
const 반환 = useQuery<데이터타입>(옵션)
useQuery 를 사용해 JSONPlaceholder라는 무료 REST API에서 사용자 목록 가져오기
// UsersList.js
import React from "react";
import { useQuery } from "@tanstack/react-query";
function UsersList() {
const { data, isLoading, error } = useQuery({
queryKey: ["users"], // 쿼리key
queryFn: async () => { // queryFn: query Function으로 데이터를 가져오는 쿼리 함수
const response = await fetch(
"https://jsonplaceholder.typicode.com/users"
);
if (!response.ok) {
throw new Error("네트워크 응답이 좋지 않습니다");
}
return response.json();
},
});
if (isLoading) { // isLoading: 쿼리 함수의 첫 번째 가져오기가 진행 중
return <div>Loading...</div>;
}
if (error) {
return <div>Error: {error.message}</div>;
}
return (
<ul>
{data.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
export default UsersList;
// App.js
import React from "react";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import UsersList from "./components/UsersList"; // UsersList 컴포넌트 가져오기
const queryClient = new QueryClient(); // QueryClient : 커스텀 쿼리 클라인트 연결.
export default function App() {
return (
<QueryClientProvider client={queryClient}>
<h1>사용자 리스트</h1>
<UsersList />
</QueryClientProvider>
);
}
// QueryClient를 생성 후, QueryClientProvider로 App을 감싸주면 앱 내의 모든 컴포넌트에서
// React Query의 기능을 사용할 수 있다.
사용자 리스트가 잘 불러와지는 걸 확인할 수 있다.
useQuery의 여러가지 옵션 참고
https://tanstack.com/query/v5/docs/framework/react/reference/useQuery
3.useInfiniteQuery
더 보기 버튼으로 추가 데이터를 더 가져오거나, 무한 스크롤 기능, 페이지네이션을 구현하기 쉽게 해주는 훅
const 반환 = useInfiniteQuery<페이지타입>(옵션)
useInfiniteQuery 를 사용해 더 보기 버튼을 클릭하여 다음 페이지의 사용자 목록을 가져오기
// UsersList.js
import React from "react";
import { useInfiniteQuery } from "@tanstack/react-query";
const fetchUsers = async ({ pageParam = 1 }) => {
const response = await fetch(
`https://jsonplaceholder.typicode.com/users?_page=${pageParam}&_limit=5`
// 페이지가 업데이트 되야되니까 동적변수로 받고, 개수는 5개로 설정
);
if (!response.ok) {
throw new Error("네트워크 응답이 좋지 않습니다");
}
return response.json();
};
export default function UsersList() {
const {
data,
isLoading,
isFetching,
hasNextPage,
fetchNextPage,
isError,
error,
} = useInfiniteQuery({
queryKey: ["users"],
queryFn: fetchUsers,
getNextPageParam: (lastPage, pages) => {
// 다음 페이지가 있으면 페이지 번호 반환, 없으면 undefined 반환
return pages.length < 10 ? pages.length + 1 : undefined; // 최대 10페이지
},
});
if (isLoading) {
return <div>Loading...</div>;
}
if (isError) {
return <div>Error: {error.message}</div>;
}
return (
<div>
<ul>
{data.pages.map((page, index) => (
<React.Fragment key={index}>
{page.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</React.Fragment>
))}
</ul>
{hasNextPage && (
<button onClick={fetchNextPage} disabled={isFetching}>
{isFetching ? "Loading..." : "더 보기"}
</button>
)}
</div>
);
}
더 보기를 누르면 5개씩 사용자 이름을 더 불러오는 것을 확인 할 수 있다.
useInfiniteQuery의 여러가지 옵션 참고
https://tanstack.com/query/v5/docs/framework/react/reference/useInfiniteQuery
4. useMutation
데이터 변경 작업(생성, 수정, 삭제 등)을 위한 훅, 데이터 변경 작업을 처리하고 다양한 성공, 실패, 로딩 등의 상태를 얻을 수 있다.
💡 쿼리(useQuery)는 '가져오기'에 집중하는 반면, 변이(useMutation)는 '보내기'에 집중하는 훅으로 이해하면 쉽다!
const 반환 = useMutation(옵션)
// UsersList.js
import React from "react";
import { useQuery } from "@tanstack/react-query";
const fetchUsers = async () => {
const response = await fetch("https://jsonplaceholder.typicode.com/users");
if (!response.ok) {
throw new Error("네트워크 응답이 좋지 않습니다");
}
return response.json();
};
export default function UsersList() {
const {
data = [],
isLoading,
isError,
error,
} = useQuery({
queryKey: ["users"],
queryFn: fetchUsers,
});
if (isLoading) {
return <div>Loading...</div>;
}
if (isError) {
return <div>Error: {error.message}</div>;
}
return (
<ul>
{data.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
// AddUser.js
import React, { useState } from "react";
import { useMutation, useQueryClient } from "@tanstack/react-query";
const addUser = async (newUser) => {
// 실제 API가 아니므로, 반환하는 데이터를 수정
return new Promise((resolve) => {
setTimeout(() => {
resolve({ id: Date.now(), ...newUser });
}, 500);
});
};
export default function AddUser() {
const [name, setName] = useState("");
const queryClient = useQueryClient();
const mutation = useMutation({
mutationFn: addUser,
onSuccess: (newUser) => {
// 사용자 목록 무효화 및 새로운 사용자 추가
queryClient.setQueryData(["users"], (old) => [...old, newUser]);
},
onError: (error) => {
console.error("사용자 추가에 실패했습니다:", error);
},
});
const handleSubmit = (e) => {
e.preventDefault();
if (name) {
mutation.mutate({ name });
setName("");
}
};
return (
<div>
<form onSubmit={handleSubmit}>
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="사용자 이름을 입력하세요."
/>
<button type="submit" disabled={mutation.isLoading}>
{mutation.isLoading ? "추가 중..." : "추가하기"}
</button>
</form>
{mutation.isError && <div>오류: {mutation.error.message}</div>}
{mutation.isSuccess && <div>사용자가 추가되었습니다!</div>}
</div>
);
}
useMutation의 여러가지 옵션 참고
https://tanstack.com/query/v5/docs/framework/react/reference/useMutation
'TIL archiving ···.ᐟ > React' 카테고리의 다른 글
Storybook (0) | 2024.10.22 |
---|---|
[React 연습] 간단한 카운터 & Todo 만들기 (1) | 2024.10.16 |
상태 관리 라이브러리 Recoil (2) | 2024.10.15 |
Context API (0) | 2024.10.14 |
React Router - useNavigate() (0) | 2024.10.10 |