진행하고 있는 프로젝트에서 react-query를 도입하려고 합니다. 그 이유와 어떻게 적용했는지 살펴보고 최종적으로 사용했을 때와 사용하지 않았을 때의 성능까지 비교해보겠습니다.
먼저 리액트쿼리에 대해 간단하게 알아보겠습니다.
react-query?
- React-Query는 데이터를 불러오고 캐싱하며, 서버 데이터와의 동기화 및 업데이트 하는 작업을 개발자가 쉽고 간단하게 할 수 있도록 도와주는 라이브러리 입니다. 즉 '비동기 로직을 쉽게 다룰 수 있게 해준다'라고 이해하면 될 것 같습니다.
데이터 캐싱기능을 잘 사용하기 위해서는 리패치가 일어나는 조건과 옵션 2가지에 대한 이해가 필요합니다.
- stale : 사전적의미로 "신선하지 않은" 리액트 쿼리는 기본적으로 캐싱된 데이터를 stale한 상태로 여깁니다. 즉, stale이란 최산화가 필요한 데이터라는 의미로 stale한 상태가 되면 refetch가 실행됩니다.
refetch가 일어나는 조건
- refetchOnWindowFcous : 윈도우에 포커스 된 경우
- refetchOnMount : 마운트 될 때
- retechOnRecoonect : 재연결 될 때
기본적으로 React Query는 위의 3가지 기능의 기본값은 모두 true 상태입니다. 이외에도 queryKey와 함께 State값을 같이 넘겨주는 경우 State값이 변경된다면 refetch가 일어나게 됩니다.
staleTime
- 데이터가 fresh -> stale 상태로 변경되는데 거리는 시간 즉, fresh 상태로 유지되는 시간
fresh한 데이터가 stale한 데이터로 변화되는 시간을 말합니다. 즉, 데이터의 유통기한이라고 생각하면 됩니다. staleTime에 대한 기본옵션은 0이고 이외에도 다른 옵션을 설정하지 않았다면 호출 즉시 stale한 상태로 변하게 되고, refetch가 일어나는 조건과 일치하게되면 데이터가 패치 됩니다.
cacheTime
데이터가 inactive 상태일 때를 기준으로 캐싱된 상태로 남아있는 시간입니다.
staleTime과는 별개로 기준 시점으로부터의 데이터의 삭제가 결정되고, cacheTime이 지나면 가비지 콜렉터로 수집됩니다.
현재 진행하고 있는 프로젝트에서 api를 이용해 데이터를 가져오는 훅입니다.
useEffect와 async await 등으로 구성되어있습니다.
import axios from "axios";
import { useState } from "react";
import { useEffect } from "react";
// axios.get을 사용할때 훅
export default function useGet(url)
{
const actoken = localStorage.accessToken;
const retoken = localStorage.refreshToken;
const [data,setData] = useState(); // api 데이터
const [loading,setLoading] = useState(false); // 데이터 로딩 상태
const [error, setError] = useState(false); // 에러 발생 상태
const getData= async()=>{
setLoading(true); //로딩시작
try{
const response = await axios.get(url,{
headers: { 'Authorization' : `Bearer ${actoken}`,
'Auth' : retoken }
});
console.log(response.data);
setData(response.data);
}catch(error){
// if(error.response.data.code==511)
// {
// alert('로그인이 만료되어 로그인 페이지로 이동합니다');
// window.location.replace('/loginpage');
// }
console.log(error);
setError(true);
}
setLoading(false);
}
useEffect(()=>{
getData();
}, [url])
return {data, loading, error};
}
react-query를 사용하면 loading useState, data useState , async-awiat문 등등을 사용할 필요가 없어집니다.
즉 아주 간결하게 몇줄만 적어주면 위의 기능이 가능해집니다.
이유
리액트 쿼리를 사용하려는 이유는 다음과 같습니다.
진행하고 있는 프로젝트 Billim이라는 중고대여사이트에서는 유저가 올린 상품들이 다른 유저들에게 보여주어야합니다. 즉 즉 상품이 대여가 되어 거래가 불가능한 상품이 될 수있고 또한 상품 작성자가 수정하여 DB에 저장된 상품에 대한 정보가 변할 수 도 있습니다. 이렇게 실시간으로 변하는 데이터에 대해 유저는 최신의 정보를 유지해야합니다. 또한 사용자가 메인페이지로 들어올때 기존의 데이터가 업데이트되지 않았는데 계속 새로 데이터를 요청한다면 성능부분에서 좋은 모습을 보이지 않습니다.
- 서버데이터캐싱기능 : 이전 페이지로 돌아왔을 때 다시 로딩되는 것이 아닌, 캐시에 저장되기 때문에 또 다시 API를 불러오는 작업이 없다.
- 실시간 업데이트 및 동기화 : 사용자의 입장에서의 데이터는 항상 최신이 유지되어야 한다.
- 요청실패시 자동으로 재시도 : 인터넷이 끊겼거나 서버가 죽었거나 그러면 ajax요청이 실패하는데 실패했을 때 재시도를 해준다.
큰 이유를 꼽자면 캐싱기능입니다. 써야하는 이유는 위와 같지만 react-query를 이론적으로만 배웠지 실제로 적용해본적은 없기 때문에 이번기회에 적용하고 싶었습니다.
설치 & 셋팅
npm install react-query
index.js파일에서 아래의 코드를 추가해줍니다. ( 1번 , 2번, 3번)
import { QueryClient, QueryClientProvider } from "react-query" //1번
const queryClient = new QueryClient() //2번
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<QueryClientProvider client={queryClient}> //3번
<Provider store={store}>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>
</QueryClientProvider>
);
그리고 hooks폴더안에 useReactQuery.js를 파일을 만들어줍니다.
url을 받아서 result값을 return해줍니다. 추가로 저는 GET방식의 데이터 호출하기 때문에 useQuery를 사용해줍니다.
useQuery의 첫번째 인수는 queryKey입니다. 해당키로 캐싱을 관리합니다. 두번째 인수는 Promise처리가 이루어지는 함수입니다. axios와 같이 서버에 API를 요청하는 코드입니다. ( useQuery는 비동기로 작동합니다 )
import axios from "axios";
import { useQuery } from "react-query";
export default function useReactQuery(url)
{
let result = useQuery(['users'],()=>{
return axios.get(url).then((a)=>{
return a.data;
})
})
console.log(result);
return result;
}
result에는 어떤 값이 담기는지 콘솔에서 확인해보겠습니다.
data에는 실제 데이터값들이 담기고 isError에는 에러가 발생했는지 유무, isLoading에는 로딩중인지에 대한 유무 등 엄청 다양한 상태들의 값을 가지고 올 수 있습니다.
부르는 곳에서는 아래처럼 선언해줍니다.
const store= useReactQuery('/api/posts');
결과(성능비교)
이전에 useGet이라는 hook을 사용하여 api요청할때입니다. 최초에 415밀리초의 시간이 걸리고
이상태에서 다른컴포넌트(다른 화면)에 갔다가 다시 메인으로 들어가면 어떤 이유인지는 모르겠지만 2번호출되어 아래처럼 대락 500밀리초의 시간이 걸립니다.
리액트쿼리를 사용했을때 최초에 사이트(메인)에 접속햇을때 372밀리초의 시간이 걸립니다.
이후 다른 컴포넌트(다른 화면)에 갔다가 다시 메인으로 들어가면 64밀리초로 확연히 줄어듭니다.
즉, 최초 데이터 패치이후에 500 -> 64로 줄어들었습니다.
'프론트엔드 > react' 카테고리의 다른 글
01. 클린코드 리액트(React) - 클린코드, Vite (0) | 2024.03.20 |
---|---|
Billim 프로젝트 화면구성 (0) | 2023.12.09 |
React - Carousel설계 ( useRef ) (1) | 2023.11.26 |
React. 최근본상품 - localStorage에 저장 (1) | 2023.10.06 |
리액트 - 서버에서 받은 UTC시간을 KST로 변환 (0) | 2023.09.15 |