RTK 와 RTK-query 관련 일화는 더 많지만 뒤에 SSR 포스트와 더 연관 있어서, 일단 이번 포스트에서는 찾아봤었던 사용법 몇 가지와 발생했던 에러 해결에 대해 이야기 하겠다.
전체 코드는 여기를 확인하길 바란다.
영화 데이터를 가져오기 위해서 header에 api key를 넣어서 보내야 했다.
RTK-query 를 이용하여 header의 값을 넣는 방법은 prepareHeaders 옵션을 이용하면 된다.
import { createApi, fetchBaseQuery, FetchBaseQueryError } from '@reduxjs/toolkit/query/react';
export const movieAPI = createApi({
reducerPath: 'movieAPI',
baseQuery: fetchBaseQuery({
baseUrl: 'https://api.themoviedb.org/3',
prepareHeaders: (headers, { getState }) => {
//headers.set(key, value) 를 이용하여 header 값 설정
headers.set('authorization', `Bearer ${process.env.NEXT_PUBLIC_API_KEY}`);
return headers;
},
}),
........
}),
});
메인 페이지 banner에 필요한 data를 가져오는 방식은 이러했다.
기존의 build.query의 query 옵션으로는 2개의 api를 한번에 다루지 못하였다. 그래서 찾아 본 결과, queryFn 옵션을 사용하면 async-await 을 사용 할 수 있고, 원하는 형태의 결과 값을 retrurn 받을 수 있다.
....
endpoints: build => ({
getRandomMoviedetail: build.query({
async queryFn(_arg, _queryApi, _extraOptions, fetchWithBQ) {
const nowPlaying = (await fetchWithBQ(`${requests.fetchNowPlaying}?language=ko-KR`)) as NowPlaying;
if (nowPlaying.error) return { error: nowPlaying.error as FetchBaseQueryError };
const movieId = nowPlaying.data.results[Math.floor(Math.random() * nowPlaying.data.results.length)].id;
const movieDetail = await fetchWithBQ(`/movie/${movieId}?append_to_response=videos&language=ko-KR`);
return movieDetail.data ? { data: movieDetail.data } : { error: movieDetail.error as FetchBaseQueryError };
},
providesTags: ['NowPlaying'],
}),
....
}),
로그인을 한 후 user 정보를 받아와서 userSlice에 넣는 과정에서 다음 과 같은 에러가 발생 했다.
“Getting an error "A non-serializable value was detected in the state" when using redux toolkit - but NOT with normal redux”
Redux에서 값을 주고, 받을 때 object 형태의 값을 string 형태로 변환(JSON.stringify)하는데, 이 상황에서 변환이 불가능한 값을 전달했을 경우 나타나는 에러라고 한다.
아마 user 정보 object 안에 또 object 가 있는데 이것이 string으로 변환이 안되서 에러가 난 것 같다.
redux store 설정 부분에서 middleware > getDefaultMiddleware > serializableCheck 옵션을 false로 설정한다.
const makeStore: MakeStore<any> = () =>
configureStore({
reducer: rootReducer,
devTools: process.env.NODE_ENV == 'development' ? true : false,
middleware: getDefaultMiddleware =>
getDefaultMiddleware({
serializableCheck: false,
}).concat(logger, movieAPI.middleware),
});
전체 코드는 여기를 확인 바란다.