React-Query와 useQuery를 어떻게 사용하는지에 대한 정리입니다.
npm i @tanstack/react-query
React Query를 사용하기 위해선 queryClient 생성 후 provider로 감싸 주어야 됩니다.
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import React from 'react';
import { createRoot } from 'react-dom/client';
import App from './App';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
const queryClient = new QueryClient(); //QueryClient 생성
const container = document.getElementById('root');
const root = createRoot(container);
root.render(
<QueryClientProvider client={queryClient}> //provider 감싸주기
<App />
<ReactQueryDevtools initialIsOpen={true} />
</QueryClientProvider>
);
이제 Query를 사용하기 위한 준비는 모두 마쳤습니다. 하지만 React Query의 편리성을 알기 위해 먼저 React Query를 사용하지 않고 진행해보겠습니다.
진행해볼 것은 todoList 할일목록을 받아와 화면에 보여주는 구현을 해보겠습니다
가짜 todoList 데이터를 가져오는 API를 예시로 자세히 알아보겠습니다.
import React from 'react';
import axios from 'axios';
import { useState, useEffect } from 'react';
import styled from 'styled-components';
import { useQuery } from '@tanstack/react=-query';
export default function App() {
const [data, setData] = useState([]);
const [isLoading, setisLoading] = useState(false);
const toDoListUrl = 'https://jsonplaceholder.typicode.com/todos';
const fetchTodos = () => {
axios.get(toDoListUrl).then((res) => {
setData(res);
setisLoading(false);
});
};
useEffect(() => {
setisLoading(true);
fetchTodos();
}, []);
if (isLoading) return <Title>is Loading...</Title>;
return (
<>
<ul>
{data.data?.slice(0, 30).map((todo) => (
<ListItem key={todo.id}>{todo.title}</ListItem>
))}
</ul>
</>
);
}
const Title = styled.h1`
font-size: 34px;
font-weight: bolder;
text-align: center;
margin: 50px auto;
`;
const ListItem = styled.li`
margin-bottom: 20px;
`;
useState로 2가지 리액트 스테이트(State)를 만들었습니다.
data는 axios로 가져오는 할일목록 데이터이고,
isLoading은 외부 API 서버와의 통신으로 발생할 수 있는 잠깐의 시간 동안 화면에 Loading... 이라는 문구를 표시하기 위한 겁니다.
그리고 실제, axios를 이용한 외부 데이터 fetching은 useEffect 훅을 이용해서 리액트 컴포넌트가 처음 시작할 때 작동하도록 했습니다.
나머지, UI 코드는 보시면 쉽게 이해할 수 있습니다.
axios는 객체를 리턴하는데 그 객체에 data라는 항목이 바로 우리가 원하는 데이터입니다.
그래서 data.data라고 이중으로 참조한 겁니다.
위 코드만으로도 데이터를 받아오고 받아오는동안 isLoading을 확인하는 것은 정상적으로 작동합니다. 하지만 React Query를 사용하면 data
와 isLoading
의 상태를 업데이트하지 않아도 데이터를 받아오고 데이터의 로딩완료 여부를 자체적으로 해주는 편리하고 강력한 기능을 사용할 수 있습니다.
import React from 'react';
import axios from 'axios';
import styled from 'styled-components';
import { useQuery } from '@tanstack/react-query';
export default function App() {
const toDoListUrl = 'https://jsonplaceholder.typicode.com/todos';
const fetchTodos = async () => {
return await axios.get(toDoListUrl);
};
const { isLoading, data } = useQuery({
queryKey: ['toDos'],
queryFn: fetchTodos,
});
if (isLoading) return <Title>is Loading...</Title>;
return (
<>
<Title>ToDo</Title>
<ul>
{data.data?.slice(0, 30).map((todo) => (
<ListItem key={todo.id}>{todo.title}</ListItem>
))}
</ul>
</>
);
}
const Title = styled.h1`
font-size: 34px;
font-weight: bolder;
text-align: center;
margin: 50px auto;
`;
const ListItem = styled.li`
margin-bottom: 20px;
`;
query 적용 후 코드를 보면 위에 설명처럼 useState없이도 데이터 fething과 is Loading 완료여부가 잘 작동하는 것을 볼 수 있습니다.
위 동작을 가능하게 해주는 것이 바로 React-query의 핵심인 useQuery
입니다.
useQuery hook을 사용하기 위해선 사용하고자 하는 파일 상단에 import 해야 됩니다.
import { useQuery } from '@tanstack/react-query'; // useQuery import
const { isLoading, data } = useQuery({
queryKey: ['toDos'], //key값 이름(자유롭게 설정 가능)
queryFn: fetchTodos, //데이터 fething 함수
});
useQuery훅을 사용하기 위해선 반드시 queryKey
값을 설정해 두어야 되는데 querykey는 반드시 배열이어야 합니다.
v4
버전 이후로 queryKey를 작성할 때는 key값만 작성하더라도 배열([]
)안에 담아줘야 합니다.
배열을 사용함으로써 아래와 같은 장점을 얻을 수 있습니다.
1. 동적으로 생성된 키를 사용하여 여러 쿼리를 추적하기에 더욱 적합하다.
2. 복잡한 키를 나타내기에 편리하다.
3. 동적으로 쿼리를 추가하거나 쿼리 그룹을 만드는 작업이 더욱 간편하다.
추가로 queryFn
에서 실행되는 함수의 실행 결과 데이터가 queryKey
안에 담깁니다.
위에서는 data와 isLoading으로만 예시를 보여드렸지만 useQuery는 보다 다양한 함수들을 지원합니다.