React Query는 클라이언트 상태 관리 라이브러리로, 주로 비동기 데이터를 다루는 데 사용
React Query 설치: 먼저 npm install @tanstack/react-query 명령어를 사용하여 React Query를 설치합니다.
쿼리 클라이언트 생성:
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
const queryClient = new QueryClient();
function App() {
return (
<QueryClientProvider client={queryClient}>
<div className="App">
<h1>Blog 'em Ipsum</h1>
<Posts />
</div>
</QueryClientProvider>
);
}
export default App;
Query Provider 적용: 생성한 쿼리 클라이언트를 사용하여 QueryClientProvider를 적용합니다. 이 과정을 통해 자식 컴포넌트들이 쿼리 클라이언트를 사용할 수 있게 됩니다.
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
const queryClient = new QueryClient();
function App() {
return (
<QueryClientProvider client={queryClient}>
{/* 여기에 앱 컴포넌트들이 위치합니다 */}
</QueryClientProvider>
);
}
useQuery 훅 사용: 서버에서 데이터를 받기 위해 useQuery 훅을 사용 이 훅은 서버에서 데이터를 비동기적으로 가져오고, 해당 데이터의 상태를 관리
import { useQuery } from '@tanstack/react-query';
function MyComponent() {
const { isLoading, error, data } = useQuery(['myData'], fetchMyData);
if (isLoading) return 'Loading...';
if (error) return 'An error has occurred: ' + error.message;
return (
<div>
{/* 데이터를 사용한 컴포넌트 로직 */}
</div>
);
}
queryKey는 배열로 지정해준다. 단일 문자열이 포함된 배열일수도 있고 여러 문자열과 중첩된 객체로 구성된 복잡한 형태일수도 있다. async function fetchPosts(pageNum = 1) {
const response = await fetch(
`https://jsonplaceholder.typicode.com/posts?_limit=10&_page=${pageNum}`
);
return response.json();
}
const { data } = useQuery({
queryKey: ["posts"],
queryFn: fetchPosts,
});
return (
<>
<ul>
{data.map((post) => (
<li key={post.id} className="post-title" onClick={() => setSelectedPost(post)}>
{post.title}
</li>
))}
</ul>
//...
</>
이럴 경우에 에러가 난다 데이터가 정의되어있지 않았기 때문에다.
Data는 fetch posts가 결과를 반환한 후에 정의(define) 되기 때문이다.
react query에는 다양한 도구가 있지만 지금은 일단 아래와 같이 해결한다.
if (!data) {
return <div />;
}
구조분해 할당이 가능하다.
const { data, isError, isLoading } = useQuery({
queryKey: ["posts"],
queryFn: fetchPosts,
});
if (isLoading) {
return <h3>Loading...</h3>;
}
if (isError) {
return <h3>Error!!</h3>;
}
isFetching 상태도 데이터를 요청하는 동안 true가 됩니다. 그러나 isLoading과 달리 데이터를 다시 불러올 때(예: 백그라운드에서의 데이터 갱신, 페이징, 무한 스크롤 등)에도 isFetching은 true가 됩니다.isFetching 상태가 사용됩니다.isFetching을 통해 로딩 상태를 표시할 수 있습니다.isLoading 상태는 쿼리가 실행되어 데이터를 처음으로 불러올 때 true가 됩니다.true로 설정되고, 데이터 로딩이 완료되거나 실패했을 때 false로 변경됩니다.크게 차이 없어보이지만 페이지네이션을 볼 때 캐시된 데이터가 있는지 없는지 구분하는 것이 중요하다.
isError 상태는 데이터를 가져오는 과정에서 오류가 발생했을 때 사용되는 상태true가 되어 피드백을 제공하거나 오류 처리 로직을 실행할 수 있게 도와줍니다.error 을 사용하면 실제 에러 내용도 확인할 수 있다.
const { data, isError, error, isLoading} = useQuery ({
///
})
기본적으로 리액트 쿼리는 3번 시도 후 데이터를 가져올수 없다고 판단한다.
시도하는 동안은 isLoading 끝나면 isError을 가져 온다.
error을 통해서 실제 어떤 에러가 발생했는지도 확인이 가능하
const { data, isError, isLoading, error } = useQuery({
queryKey: ["posts"],
queryFn: fetchPosts,
});
if (isLoading) {
return <h3>Loading...</h3>;
}
if (isError) {
return (
<>
<h3>Error!!</h3>
<p>{error.toString()}</p>
</>
);
}