React-Query
리액트쿼리는 데이터 패칭, 캐싱, 동기화, 서버쪽 데이터 업데이트 등을 쉽게 만들어주는 리액트 라이브러리이다.
처음에는 이 리액트쿼리가 서버를 연결시켜주는 역할인줄 알았으나 리액트 쿼리의 옵션 등을 사용하여 좀 더 편리하게 데이터 관리를 할 수 있는, 말그대로 옵션이었다.
특징
1. queryKey를 사용하여 데이터가 캐싱되고, useEffect로 데이터 상태 관리 및 패칭하던 것을 좀 더 간단하게 구현 가능(페이지네이션, 검색 기능 등). 이것은 sideEffect를 줄이고 코드를 간결하게 작성하도록 한다.
2. 다양한 옵션을 사용하여 복잡하게 코드를 작성해야 하는 것을 간단하게 구현 가능(동기적으로 패칭 및 자동 리패칭 등)
3. isLoading, isFetching, isSuccess, isError등과 같은 여러 상태 처리 가능
사용법
1. 먼저 최상단인 app 컴포넌트에서 쿼리 인스턴스를 생성하고 QueryClientProvider로 감싸줘야한다.
import { QueryClient, QueryClientProvider } from "react-query";
const queryClient = new QueryClient(); //쿼리 인스턴스 생성
export default function App() {
return (
<QueryClientProvider client={queryClient}>
<Home />
</QueryClientProvider>
);
}
2. 리액트 쿼리에서는 서버에 연결할 때 때 두가지 방법을 사용한다.
1) useQuery : 데이터를 조회할 때(crud의 read)
2) useMutate : 서버에 데이터 변경 작업을 요청할 때 사용(crud의 insert, update, delete)
먼저 useQuery에 대해 알아보자
useQuery
- 서버로부터 데이터 조회 시 사용(get)하며 crud 중 reading 에만 해당한다.
- useQuery는 비동기로 작동한다. 즉, 한 컴포넌트에 여러개의 useQuery가 있다면 하나가 끝나고 다음 useQuery가 실행되는 것이 아닌 두 개의 useQuery가 동시에 실행된다.
- 여러개의 비동기 query를 사용해도 되지만 useQuery보다는 useQueries 사용을 권한다.
const { data, isLoading, error } = useQuery(queryKey, queryFn, options)
반환값 매개변수
useQuery는 위와 같이 사용할 수 있으며, 사용할 반환값을 작성하고 3개의 매개변수를 가진다.
매개변수
1) queryKey : useQuery마다 부여되는 고유 Key 값
- 하나의 string 또는 배열로 지정 가능 : 하나의 key만 넣을 때는 string으로 그냥 넣어도 되고(내부적으로 자동으로 배열 안에 넣게 바꿈), 둘 이상부터는 배열을 선언하여 안에 넣어야 한다.
- 데이터 캐싱 관리 : 동일한 queryKey를 사용하여 서버의 데이터를 추가 조회하는 경우 추가로 요청하는 것이 아니라 이미 동일한 queryKey에 대한 결과값이 있기 때문에 해당 값을 그대로 가져와 사용 → 다른 컴포넌트에서도 해당 키를 사용하면 호출 가능하며, queryKey가 같으면 캐싱 적용하고 queryKey가 다르면 서버에서 데이터 다시 fetch한다. -> 이것을 이용해서 검색/페이지네이션을 간편하게 구현할 수 있다.
const { data: courseData, error: courseError } = useQuery(['courseGet', page], () =>
GET(`/course/***`, {
params: { page, elementCnt: limit }
})
);
→ queryKey에 배열로 page를 추가하여 page가 변경되면 쿼리키가 변경되므로 데이터가 리패치된다(=페이지네이션에서 현재페이지를 page로 설정하고 이 현재페이지가 변경되면 데이터가 리패치된다). 이렇게 하면 useEffect를 사용하여 page 변경될 때 마다 렌더링되도록 하는 작업을 따로 만들지 않아도 된다.
2) queryFn : api 호출 함수
query Function으로 promise 처리가 이루어지는 비동기 함수가 들어간다(promise 를 반환하는 함수) → 데이터 resolve하거나 error를 보내고, 보통 fetch나 axios를 사용하여 서버 연결 요청을 보내는(서버에 api 요청하는) 함수를 인자로 받는다.
3) option : 데이터 패치 시 좀 더 간편하게 다양한 기능들을 사용할 수 있으며 선택사항이다.
- enabled : 원하는 시점에 실행되도록(비동기를 동기로 처리할 때)
- retry: query 동작 실패 시, 자동으로 retry 할지 결정하는 옵션
- keepPreviousData : 새롭게 fetching 시 이전 데이터 유지 여부(탭 이동시 또는 페이지네이션에서 깜빡거리는 현상 제거)
- refetchInterval : 주기적으로 refetch 할지 결정하는 옵션
- refetchOnWindowFocus : 윈도우 포커스 시 자동 리패치 조절
// 1
const res = useQuery(['persons'], () => axios.get('<http://localhost:8080/persons>'));
// 2
const res = useQuery({
queryKey: ['persons'],
queryFn: () => axios.get('<http://localhost:8080/persons>')
});
즉, 첫번째 매개변수에는 캐시를 관리할 키값이 들어가고, 두번째 매개변수는 실질적으로 어디에 api를 패칭해서 가져올건지를 정의하는 Promise 함수가 들어간다.
반환값
- data : 마지막으로 성공한 resolve된 데이터(response)
- error : 에러가 발생했을 때 반환되는 객체
- isFetching : 요청이 in-flight 중일 때 true
- status, isLoading, isSuccess, isLoading 등 : 모두 현재 query의 상태
- refetch : 해당 query refetch하는 함수 제공
- remove : 해당 query cache에서 지우는 함수 제공
예시
//course.ts - api연결하는 코드는 이 파일에 모두 작성하고 데이터가 필요한 컴포넌트에서 해당 데이터를 불러온다
//차시+차시진도 데이터 조회 ✅
//courseModuleSeq, courseUserSeq, chasiName이라는 세개의 매개변수를 받는 chasiProgressApi 함수
//? : optional properties - 이 매개변수에 값을 할당하지 않아도 작업이 실행되며, chasiName에 값이 할당될 경우 chasiName의 값이 포함된 데이터만 가져온다(=검색기능)
export const chasiProgressApi = ({
courseModuleSeq,
courseUserSeq,
chasiName
}: {
courseModuleSeq: number;
courseUserSeq: number;
chasiName?: string;
}) => {
return useQuery(
['progressApi', { courseModuleSeq }], //모듈시퀀스가 변경될 때마다 리패치
async () => {
const response = await GET(`/module/${courseModuleSeq}/***`, {
params: { courseUserSeq, courseModuleSeq, chasiName, page: 1, sort: 'old' }
});
return response; //chasiProgressApi에 이 리턴값이 저장된다
},
{//option
keepPreviousData: true, // 모듈 이동시 깜박거리는 현상 제거 - ux향상
refetchOnWindowFocus: false // 윈도우 포커스 시 자동 리패치 방지
}
);
};
//course.tsx - chasiProgressApi 함수를 호출하여 데이터를 가져온다 ✅
const { data: chasiData, refetch } = chasiProgressApi({ //해당 데이터는 chasiData에 할당된다
courseModuleSeq: courseModuleSeq,
courseUserSeq: courseUserSeq,
chasiName: searchKeyword
});
* keepPreviousData가 버전 5에서는 placeholderData: previousData => previousData, 로 변경
'React' 카테고리의 다른 글
| [한입리액트] useRef : 컴포넌트가 리렌더링 되더라도 값이 초기화되지않고 유지시키고 싶을 때 사용 (2) | 2023.07.27 |
|---|---|
| [React-Query] 2. useMutation 사용하기(공부중...) (0) | 2023.06.27 |
| [React-Query] 1. 리액트쿼리 들어가기 전 Axios 알아보기 (0) | 2023.05.31 |
| [새싹 프론트앤드] react 메뉴 클릭 시 글자 색 변경 유지하기(NavLink) (0) | 2023.01.15 |
| [새싹 프론트엔드] typeScript로 todo-list 만들기 (0) | 2022.12.18 |