RTK Query
Redux Toolkit의 강력한 데이터 패칭 및 캐싱 라이브러리
1. 데이터 패칭 및 캐싱
2. 자동 상태 관리
- API 요청의 상태(isLoading, isSuccess, isError, isFetching 등)를 자동으로 관리
- 수동으로 로딩 상태를 설정하거나 에러를 처리할 필요 X
3. 데이터 변조 지원
- POST, PUT, DELETE 요청과 같은 데이터 변조 작업도 간단히 구현 가능
4. React Hooks 자동 생성
- API 엔드포인트 정의만 하면 React Hooks가 자동으로 생성됨.
- 이를 통해 컴포넌트에서 쉽게 API를 호출할 수 있음.
RTK Query의 주요 구성 요소
1. createApi
API 서비스 로직을 정의하는 데 사용
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
export const api = createApi({
reducerPath: 'api', // Redux store에 저장될 리듀서의 이름
baseQuery: fetchBaseQuery({ baseUrl: '/api' }), // 기본 요청 설정
endpoints: (builder) => ({
// 엔드포인트 정의
}),
});
2. baseQuery
모든 API 요청에 공통적으로 적용될 설정 정의
- 기본 URL, 인증 헤더 추가, 에러 처리 등 포함
const baseQuery = fetchBaseQuery({
baseUrl: 'https://api.example.com',
prepareHeaders: (headers, { getState }) => {
const token = getState().auth.token;
if (token) {
headers.set('Authorization', `Bearer ${token}`);
}
return headers;
},
});
3. endpoints
API 요청 로직을 정의하는 곳.
builder.query와 builder.mutation을 사용해 GET 요청과 POST/PUT/DELETE 같은 데이터 변조 요청 설정
export const api = createApi({
reducerPath: 'api',
baseQuery: fetchBaseQuery({ baseUrl: '/api' }),
endpoints: (builder) => ({
getUser: builder.query({
query: (id) => `/user/${id}`, // GET 요청
}),
updateUser: builder.mutation({
query: (user) => ({
url: `/user/${user.id}`,
method: 'PUT',
body: user, // PUT 요청에 전송할 데이터
}),
}),
}),
});
이렇게 createApi로 API를 정의하면, 자동으로 React Hooks를 생성한다.
export const { useGetUserQuery, useUpdateUserMutation } = api;
이렇게 만들어진 리액트 훅들은 이렇게 사용할 수 있다.
const { data, error, isLoading } = useGetUserQuery(userId);
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return <div>{data.name}</div>;
RTK Query의 캐싱
RTK Query는 동일한 요청 데이터에 대해 자동으로 캐싱한다.
데이터가 이미 캐싱되어 있다면 서버 요청 없이 캐시 데이터 반환!
const { data, refetch } = useGetUserQuery(userId, { pollingInterval: 10000 }); // 10초마다 데이터 갱신
RTK Query의 상태 관리
RTK Query는 API 요청의 상태를 자동으로 관리하며, 다음과 같은 상태 값 제공!
- isLoading : 요청이 진행 중인지 여부
- isSuccess : 요청이 성공적으로 완료되었는지 여부
- isError : 요청이 실패했는지 여부
- isFetching : 새로운 데이터를 가져오는 중인지 여부
우선 createApi를 사용해서 API 요청 로직을 작성해보자.
import { createApi } from '@reduxjs/toolkit/query/react';
import baseQuery from './baseQuery';
export const userApi = createApi({
reducerPath: 'userApi', // 리듀서 경로 이름
baseQuery,
endpoints: builder => ({
signUp: builder.mutation({
query: newUser => ({
url: '/user/signup', // 회원가입 엔드포인트
method: 'POST',
body: newUser, // 요청 데이터
headers: {
'Content-Type': 'application/json',
},
}),
}),
}),
});
export const { useSignUpMutation } = userApi;
reducerPath는 Redux Store에 저장될 리듀서의 키 이름이다.
그리고 baseQuery에는 기본 URL과 인증 헤더가 들어가 있다!
endpoints에는 builder를 통해 query(GET 요청)과 mutation(POST, PUT, DELETE 요청)을 설정할 수 있다.
회원가입 시에는 데이터를 보내야 하기 때문에, mutation을 설정해 주었다. (newUser가 함수 호출 시 전달되는 사용자 데이터)
이렇게 정의하고 나면 useSignUpMutation이라는 훅이 완성된다!
이렇게 createApi로 정의된 API는 Redux Store에 연결해야 사용할 수 있다.
// store.ts
import { configureStore } from '@reduxjs/toolkit';
import { userApi } from './userApi'; // createApi로 정의한 API
export const store = configureStore({
reducer: {
// RTK Query 리듀서를 등록
[userApi.reducerPath]: userApi.reducer,
},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().concat(userApi.middleware), // RTK Query 미들웨어 추가
});
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
아까 정의한 리듀서 경로 이름으로 리듀서를 등록해준다.
Redux에서 미들웨어는 액션이 리듀서로 전달되기 전에 가로채서
추가적인 작업(ex. 로깅, 비동기 처리, API 호출 등)을 수행할 수 있는 기능이다.
RTK Query에서는 미들웨어가 데이터 패칭과 캐싱, 상태 관리를 자동으로 처리하는 데 사용된다!
그리고 Redux Store를 또 React 컴포넌트 트리에 연결해 주어야 한다.
import { Provider } from 'react-redux';
import { store } from './store'; // Redux Store
function MyApp({ Component, pageProps }) {
return (
<Provider store={store}>
<Component {...pageProps} />
</Provider>
);
}
export default MyApp;
이렇게 하면 RTK Query에서 상태 관리와 API 호출을 사용할 수 있게 된다!
const [signUpUser, { isLoading }] = useSignUpMutation(); // isError, isSuccess
사용하려는 컴포넌트에서 useSignUpMutation 훅을 불러온다.
isLoading은 버튼의 disabled 속성에 넣어 주었고, isError, isSuccess는 회원가입 실패/성공 시 토스트 띄울 때 사용할 예정!
const onSubmit = async (data: SignUpSchema) => {
try {
// 필수 항목 + 선택 항목 데이터 합치기
const userData = {
...omit(data, 'confirmPassword'), // confirmPassword 제거
birthday: selectedDate || '1925-01-01',
...(selectedGender !== '선택안함'
? { gender: selectedGender === '여성' ? 'female' : 'male' }
: {}),
};
// API 호출
const result = await signUpUser(JSON.stringify(userData)).unwrap();
console.log('회원가입 성공:', result);
} catch (err) {
console.error('회원가입 실패:', err);
}
};
회원가입 폼 제출 시 실행되는 함수에 API 호출 로직을 추가했다.
API 호출은 비동기 작업이니까 async, await도 추가해주고, signUpUser에 데이터를 담아서 API를 호출한다.
데이터는 json 형식으로 보내야 하기 때문에 JSON.stringify() 메서드도 사용해 주었다.
try/catch로 에러도 잡아준다!
unwrap()는 API 호출 결과에서 성공과 실패를 Promise 기반으로 처리할 수 있도록 도와주는 메서드이다.
성공 시 data를 반환하고, 실패 시 error를 반환하도록!
이렇게 하면 회원가입 성공 시 result로 data가 반환되고, 실패 시 error가 반환된다.
RTK Query는 처음 사용해 보는데, 간편하고 좋은 것 같다.
로그인이랑 유저 정보 받아오는 API 호출 로직도 다 함께 작성이 가능하다.
하지만 어렵다.....
'개발 > 프로젝트' 카테고리의 다른 글
redux-persist로 Redux 상태 유지하기 (0) | 2025.01.08 |
---|---|
RTK Query로 로그인 API 구현하고 RTK로 유저 정보 관리하기 (0) | 2025.01.07 |
react-hook-form, zod를 활용하여 회원정보 수정 페이지 제작하기 (1) | 2025.01.04 |
dayjs를 활용하여 생년월일 선택하는 드롭다운 생성하기 (1) | 2024.12.28 |
cva, clsx를 활용하여 레이어팝업 컴포넌트 만들기 (2) | 2024.12.27 |