농담반 진담반으로 리액트로 프론트엔드를 구성할 때 다른 스택은 양보해도 React-Query는 절대 양보하지 않는다..
그래서 React-Query 소개와 함께 내가 사용하는 노하우를 공유하려고 한다.
개요
대부분의 프론트엔드는 비동기 상태 관리가 필요하다.
각자 다양한 방식으로 구성하겠지만 현재 가장 많이 사용되는 방식은 Redux일 것이라고 생각이 든다.
분명 Redux도 좋은 상태 관리 툴이지만 나는 비동기 상태 관리 스택으로 채택하지 않는다.
두 가지 정도 이유가 있는데 이유를 간단히 설명하자면
우선 Redux는 비동기에 특화된 스택이 아니기 때문에 비동기 처리에 도움을 크게 주지 못한다.
예를 들어 비동기 요청을 일정한 텀마다 보내야 한다면 Redux에서는 직접 구현해야 하지만 React-Query는 옵션만 추가하면 알아서 관리해준다.
이뿐만 아니라 다양한 옵션들을 제공해 준다.
두 번째 이유는 코드 양이 너무 많아진다는 점이다.
아마 이 이유는 따로 설명하지 않아도 Redux를 사용하는 사람들은 공감할 것 같다.
그래서 React-Query가 뭔데?
간단히 한 줄로 요약하자면 Key를 통해 비동기 데이터(Server State)를 관리하는 툴이다.
강력한 특징으로는 비동기를 도와주는 옵션들이 많다는 점과 캐싱이 있다고 생각한다.
useQuery
GET Method(Data Read)를 도와주는 훅으로 useQuery라는 훅이 있다.
이 훅을 하나씩 뜯어보자
// api.ts
export const getCampaignList = (naverId: string) => {
return axiosInstance
.get<ICampaignList>('/naver/campaigns', {
params: {
naver_id: naverId,
},
})
.then((r) => r.data);
};
// foo.tsx
const { data, status } = useQuery(['campaign', userData ? userData.user_id : ''], () =>
getCampaignList(userData ? userData.user_id : ''),
);
return (
<>
{
status === 'loading' ? <Loading /> : data.map(v => <Item value={v} />)
}
</>
)
Basic
먼저 기본적으로 parameter와 return값을 소개하자면
parameter
1. key: 서버 데이터에 대해 캐시를 저장하는 기준의 key로 같은 key를 다른 곳에서도 사용한다면 여기서 받아왔던 값을 사용할 수 있다.
예를 들어 위 경우 같은 userData.user_id는 같은 캐싱 데이터를 사용한다.
2. queryFn: 데이터를 요청하는 비동기 함수로 Promise<T>를 반환하는 함수이다.
return
1. data: queryFn으로 받아온 데이터로 타입은 (T | null)이다
2. status: 현재 비동기의 상태로 (idle, error, loading, success)가 있다.
useQuery를 기본적으로만 사용하기 위해서는 위 parameter와 return만을 사용해도 충분하지만 유용한 다른 옵션, 반환 값들이 있다.
Optional
Option
먼저 parameter에 option을 추가해 다양한 기능들을 활용할 수 있다. 그중 자주 사용하는 option들을 소개하자면
const { status, data, refetch } = useQuery(
['dashboard', startDate, endDate, isAscending, sortTarget, keyword, userData?.user_id, page],
() =>
getDashboardData(
startDate as Date,
endDate as Date,
isAscending,
sortTarget,
keyword,
userData.user_id
page,
),
{
placeholderData: dashboardPreviewData,
enabled: userData !== null && startDate !== undefined && endDate !== undefined,
onError: (err: any) => {
alert(err.response.data.detail);
if (err.response.data.detail === 'ID not found') {
removeLoginId();
router.push('/');
}
},
onSuccess: (v) => {
if (v.page_number < page) {
setPage(v.page_number);
}
},
refetchInterval: 5000,
},
);
1. placeholderData: 이 값을 비동기 데이터를 불러오기 전에 사용하는 값으로 View를 미리 그려놓고 싶을 때 매우 유용하다 이 값을 사용하면 Layout Shift를 줄일 수 있기 때문에 사용자 경험을 향상할 수 있어 자주 사용한다.
2. enabled: 특정 조건까지 비동기 데이터를 불러오고 싶지 않을 때 사용하는 옵션으로 위와 같이 특정 데이터를 설정하기 전까지 요청을 막을 수 있다.
3. OnSuccess, onError: 비동기 요청 성공, 실패 시 필요한 로직을 적을 수 있다.
4. refetch~: 비동기 요청을 다시 하는 조건에 대해 정의할 수 있는 옵션으로 Interval, Mount, Focus와 같은 조건에서 다시 요청할 수 있도록 도와준다.
5. refetch: Hook의 옵션이 아닌 반환 값으로 수동으로 비동기 요청을 다시 하는 함수이다.
몇 가지 옵션들이 더 있지만 주로 사용하는 값들을 위와 같다.
특히 placeholderData UX 향상에 큰 도움을 주고, enabled는 코드 양을 줄이는 데에 큰 도움을 주기 때문에 애용하는 편이다.
글을 정독했다면 GET(read)은 이렇게 처리하면 되지만 서버에 사이드 이펙트를 발생시키는 POST, DELETE와 같은 메서드들을 어떻게 처리하는지 궁금할 수도 있을 것 같다 이 메서드들을 useMutation을 사용하는데 이 훅은 다른 글에서 소개해볼 계획이다.
'front-end > react' 카테고리의 다른 글
React의 Virtual DOM은 어디에 저장될까? (1) | 2024.02.13 |
---|---|
React 19가 다가온다 (2) | 2024.01.28 |
리액트 패턴 | Compound Components Pattern (0) | 2023.08.24 |
Vercel Postgres - Frontend를 위한 Serverless SQL Database (2) | 2023.05.07 |
Tailwind CSS vs Styled-components 비교 (2) | 2023.03.05 |