냥냠
[React] Redux-toolkit 간단한 사용법 본문
redux-toolkit의 사용 방법
넷플릭스 클론 코딩 중에 리덕스 관리를 기존 리덕스에서 리덕스 툴킷으로 바꾸는 과정 기록
* 설치 코드
npm install redux react-redux @reduxjs/toolkit
yarn add redux react-redux @reduxjs/toolkit
기존의 리덕스를 사용할 때에는 몇 가지 문제점이 있었다.
- 스토어 복잡성
- 반복되는 코드 작성
- 다양한 패키지 설치
등등
여러 가지 이유로 기존의 리덕스보다 리덕스 툴킷을 이용하면 더 좋다고 한다.
리덕스 툴킷에 포함된 기능
- configureStore : 기존의 createStore 대신 간단하게 Store를 만들 수 있게 해준다.
- createReducer : 기존의 switch문 대신 간단하게 리듀서를 만들 수 있게 해준다.
- createAction : 리듀서에 작성한 것을 기반으로 action을 만들어 준다.
- createSlice : reducer의 이름, 초기 상태, 리듀서들을 간편하게 만들어 준다.
기존과는 다르게 함수형으로 만들어 쓸 수 있다.
- createAsyncThunk : createAction을 비동기로 만들어 준다.
- createSelector : store의 상태를 효율적으로 저장하게 해준다.
redux 폴더 구조
action과 reducers은 역할에 맞는 파일을 각각 생성해준다.
- store.js
import { configureStore } from '@reduxjs/toolkit'
import movieReducer from './reducers/movieReducer'
const store = configureStore({
reducer: {
movies: movieReducer,
}
})
export default store;
기존에는 reducer들을 통합해주는 combineReducers로 합쳐 rootReducer.js 혹은 index.js라는 파일을 또 만들어서 사용했지만
Redux-Toolkit을 사용하면 configureStore로 여러 reducer를 담을 수 있다.
- action.js (비동기처리 X)
기존에는 ActionType을 만들어줘야 했지만 툴킷을 사용하면 리듀서에서 createSlice에서 만든 것을 바탕으로
action을 추출해낼 수 있기 때문에 만들 필요가 없다.
import api from "../api";
import { getMoviesSuccess, getMoviesRequest , getMoviesFailure} from "../reducers/movieReducer";
function getMovies() {
return async (dispatch) => {
try {
dispatch(getMoviesRequest())
const popularApi = api.get('/movie/popular?language=en-US&page=1');
const topRateApi = api.get('/movie/top_rated?language=en-US&page=1');
const upComingApi = api.get('/movie/upcoming?language=en-US&page=1');
const genreApi = api.get('/genre/movie/list?language=en');
let [popularMovies, topRateMovies, upComingMovies, genreList] = await Promise.all([popularApi, topRateApi, upComingApi, genreApi ]);
dispatch(getMoviesSuccess({
popularMovies: popularMovies.data, // results 사용
topRateMovies: topRateMovies.data,
upComingMovies: upComingMovies.data,
genreList:genreList.data.genres,
}));
} catch (error) {
//에러 핸들링
dispatch(getMoviesFailure())
}
};
}
export const movieAction = {
getMovies,
};
이 코드는 비동기처리 없이 툴킷을 사용하려고 기존의 리덕스에서 바꾼 코드이다. (툴킷을 완전하게 사용 X)
하지만 이렇게 되면 비동기 작업을 수동으로 처리해야 하고 액션의 이름을 명시적으로 작성해야 한다.
기존에는 미들웨어인 thunk 나 saga를 이용해서
redux-toolkit에서 비동기 처리는 createAsyncThunk를 사용하게 되는데
이전과 비슷하지만 다른 점은 try-catch문을 쓰지 않아도 된다는 것이다.
*createAsyncThunk() 속성
createAsyncThunk(typePrefix: string, payloadCreator: AsyncThunkPayloadCreator,
options?: AsyncThunkOptions): AsyncThunk
-action.js(비동기 처리 O)
import { createAsyncThunk } from '@reduxjs/toolkit';
import api from '../api';
export const fetchMovies = createAsyncThunk(
'movies/fetchMovies',
async () => {
const popularApi = api.get('/movie/popular?language=en-US&page=1');
const topRateApi = api.get('/movie/top_rated?language=en-US&page=1');
const upComingApi = api.get('/movie/upcoming?language=en-US&page=1');
const genreApi = api.get('/genre/movie/list?language=en');
let [popularMovies, topRateMovies, upComingMovies, genreList] = await Promise.all([popularApi, topRateApi, upComingApi, genreApi]);
return {
popularMovies: popularMovies.data,
topRateMovies: topRateMovies.data,
upComingMovies: upComingMovies.data,
genreList: genreList.data.genres,
};
}
);
- reducer.js (비동기 처리 X)
초기설정하는 것은 변함없고 switch문으로 action 타입에 따라 나눠줘야 했던 기존의 리듀서와는 다르게
createSlice를 사용해서 action에 따른 reducer를 작성해주면 된다.
import { createSlice } from "@reduxjs/toolkit";
let initialState = {
popularMovies: {},
topRateMovies:{},
upComingMovies:{},
loading:true,
genreList:[]
}
const movieSlice = createSlice({
name: "movies",
initialState,
reducers: {
getMoviesSuccess(state, action) {
state.popularMovies = action.payload.popularMovies;
state.topRateMovies = action.payload.topRateMovies;
state.upComingMovies = action.payload.upComingMovies;
state.loading = false;
state.genreList = action.payload.genreList;
},
getMoviesRequest(state){
state.loading = true;
},
getMoviesFailure(state){
state.loading = false;
},
},
});
export const { getMoviesSuccess, getMoviesRequest, getMoviesFailure} = movieSlice.actions;
export default movieSlice.reducer;
-reducer.js( 비동기 처리 O)
비동기 처리할 때의 대표적인 3가지 상태이다.
- pending : 비동기 호출 이전
- fulfilled : 비동기 호출 성공
- rejected : 비동기 호출 실패
extraReducers를 사용하여 비동기 상태를 쉽게 제어할 수 있다.
import { createSlice } from "@reduxjs/toolkit";
import { fetchMovies } from './movieAction'; // fetchMovies 가져오기
const movieSlice = createSlice({
name: "movies",
initialState: {
popularMovies: [],
topRateMovies: [],
upComingMovies: [],
genreList: [],
loading: true,
error: null
},
reducers: {},
extraReducers: (builder) => {
builder
.addCase(fetchMovies.pending, (state) => {
state.loading = true;
state.error = null;
})
.addCase(fetchMovies.fulfilled, (state, action) => {
state.popularMovies = action.payload.popularMovies;
state.topRateMovies = action.payload.topRateMovies;
state.upComingMovies = action.payload.upComingMovies;
state.genreList = action.payload.genreList;
state.loading = false;
})
.addCase(fetchMovies.rejected, (state, action) => {
state.loading = false;
state.error = action.error.message;
});
},
});
export default movieSlice.reducer;
dispatch 하는 방법
- Home.js
import { fetchMovies } from '../redux/actions/movieAction';
const dispatch = useDispatch();
const { popularMovies, topRateMovies, upComingMovies, loading } = useSelector(
(state) => state.movies
);
useEffect(() => {
dispatch(fetchMovies());
},[dispatch])
... 이하 코드
참고
redux-toolkit에서 비동기 처리하기
redux-toolkit에서 createAsyncThunk로 비동기 처리하기
velog.io
https://fomaios.tistory.com/entry/React-Native-Redux-Toolkit%EC%9D%B4%EB%9E%80
[React Native] Redux-Toolkit이란? (feat. 기존 Redux와 비교)
안녕하세요. Foma 입니다! 저번 글에서 Redux가 무엇이고 어떻게 사용하는지에 대해 다뤘었는데요. (아직 안 보신 분들은 여기 에서 보시면 됩니다!) Redux에 대해 찾아보니 Redux를 사용하기 쉽고 효
fomaios.tistory.com
'React' 카테고리의 다른 글
[React] react 웹 사이트 반응형으로 구현하는 방법 (2) | 2024.09.10 |
---|---|
[React] Pagination 구현하기(mui) (0) | 2024.08.23 |
[React] React 기초(3) _ Redux (1) | 2024.07.16 |
[React] React 기초 (2) _Router (0) | 2024.07.12 |
[React] React 기초 (1) (0) | 2024.07.11 |