[Youtube-clone 팀 프로젝트] React 활용한 유튜브 "메인화면" Redux 적용 방법 및 회고 - 4
깃허브 주소
https://github.com/PrograMemo-Groom/youtube-clone
GitHub - PrograMemo-Groom/youtube-clone: [Team 1] prograMemo youtube-clone site
[Team 1] prograMemo youtube-clone site. Contribute to PrograMemo-Groom/youtube-clone development by creating an account on GitHub.
github.com
배포사이트 주소
https://programemo-youtube.netlify.app/
PrograMemo Youtube
programemo-youtube.netlify.app
안녕하세요 이번에는 Redux Toolkit을 적용한 메인화면에 대해 이야기 나눠보려고 합니다.
MainVideo.js에 MainReducer.js를 임포트해서 사용했는데, MainVideo.js에 대한 자세한 내용은 아래 포스터를 참고해주세요.
[Youtube-clone 팀 프로젝트] React 활용한 유튜브 "메인 화면" 제작 및 회고 - 1
깃허브 주소https://github.com/PrograMemo-Groom/youtube-clone GitHub - PrograMemo-Groom/youtube-clone: [Team 1] prograMemo youtube-clone site[Team 1] prograMemo youtube-clone site. Contribute to PrograMemo-Groom/youtube-clone development by creating a
uplifted.tistory.com
Redux Toolkit으로 구현한 비디오 데이터 상태 관리
Redux Toolkit은 Redux를 간결하고 효율적으로 사용할 수 있도록 돕는 도구입니다.
이번 글에서는 Redux Toolkit을 활용하여 유튜브 비디오 데이터를 비동기적으로 가져오고 상태를 관리하는 방법을 소개합니다.
MainReducer.js
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import { getMainVideos } from "../../service/MainService";
// 비디오 데이터를 비동기로 가져오는 Thunk 생성
export const fetchVideos = createAsyncThunk(
"videos/fetchVideos",
async ({ categoryId, pageToken }, { rejectWithValue }) => {
try {
const response = await getMainVideos(categoryId, pageToken);
return {
videos: response.videos, // API에서 받은 비디오 데이터
nextPageToken: response.nextPageToken, // API에서 받은 다음 페이지 토큰
};
} catch (error) {
return rejectWithValue(error.message);
}
}
);
// Slice 정의
const MainReducer = createSlice({
name: "videos",
initialState: {
videoList: [], // 비디오 데이터
nextPageToken: null,
loading: false,
error: null, // 에러 메시지
},
reducers: {
reset: (state) => {
state.videoList = [];
state.nextPageToken = null;
state.loading = false;
state.error = null;
},
}, // 필요 시 동기 액션 추가
extraReducers: (builder) => {
// fetchVideos 상태 처리
builder
.addCase(fetchVideos.pending, (state) => {
state.loading = true;
state.error = null;
})
.addCase(fetchVideos.fulfilled, (state, action) => {
const { videos, nextPageToken } = action.payload;
state.videoList = [...state.videoList, ...videos];
state.nextPageToken = nextPageToken;
state.loading = false;
})
.addCase(fetchVideos.rejected, (state, action) => {
state.error = action.payload;
state.loading = false;
});
},
});
export const { reset } = MainReducer.actions;
export default MainReducer.reducer;
1. Redux Toolkit의 주요 구성 요소
1) createSlice
createSlice는 Redux 상태와 리듀서를 한 곳에 정의할 수 있는 함수입니다.
initialState, reducers, extraReducers를 통해 상태 초기화와 동기/비동기 액션을 처리합니다.
2) createAsyncThunk
createAsyncThunk는 비동기 작업을 간편하게 처리할 수 있는 도구입니다.
비동기 호출 로직과 상태 업데이트를 분리하여 코드 가독성을 높여줍니다.
2. 비동기 작업 처리: fetchVideos
1) fetchVideos의 역할
fetchVideos는 비디오 데이터를 API에서 가져오는 비동기 작업을 처리합니다.
이 함수는 createAsyncThunk를 사용하여 정의되며, 다음과 같은 로직을 포함합니다
export const fetchVideos = createAsyncThunk(
"videos/fetchVideos",
async ({ categoryId, pageToken }, { rejectWithValue }) => {
try {
const response = await getMainVideos(categoryId, pageToken);
return {
videos: response.videos,
nextPageToken: response.nextPageToken,
};
} catch (error) {
return rejectWithValue(error.message);
}
}
);
구성 요소
1. 비동기 API 호출
getMainVideos 함수를 호출하여 API로부터 비디오 데이터를 가져옵니다.
2. 성공 시 데이터 반환
response.videos와 response.nextPageToken을 반환하여 상태를 업데이트
3. 실패 시 에러 처리
rejectWithValue를 사용하여 에러 메시지를 상태에 저장
2) fetchVideos의 상태 처리
createAsyncThunk에서 반환되는 상태(pending, fulfilled, rejected)는 extraReducers에서 처리됩니다.
extraReducers: (builder) => {
builder
.addCase(fetchVideos.pending, (state) => {
state.loading = true;
state.error = null;
})
.addCase(fetchVideos.fulfilled, (state, action) => {
const { videos, nextPageToken } = action.payload;
state.videoList = [...state.videoList, ...videos];
state.nextPageToken = nextPageToken;
state.loading = false;
})
.addCase(fetchVideos.rejected, (state, action) => {
state.error = action.payload;
state.loading = false;
});
},
- pending: 데이터 로딩 상태를 설정
- fulfilled: 성공적으로 데이터를 가져왔을 때
- 기존 videoList에 새 데이터를 추가
- nextPageToken을 업데이트하여 다음 페이지 로드 준비
- rejected: 에러 발생 시 error 상태에 에러 메시지 저장
3. Slice 정의: MainReducer
MainReducer는 Redux의 상태 관리 로직을 정의한 슬라이스입니다.
1) initialState
initialState: {
videoList: [],
nextPageToken: null,
loading: false,
error: null,
}
- videoList: API에서 가져온 비디오 데이터의 리스트
- nextPageToken: 다음 페이지 데이터를 가져올 때 필요한 토큰
- loading: 데이터 로딩 상태
- error: 에러 메시지를 저장
2) 동기 리듀서: reset
reset: (state) => {
state.videoList = [];
state.nextPageToken = null;
state.loading = false;
state.error = null;
}
- 역할: reset 액션을 호출하면 상태를 초기화합니다.
예를 들어, 새 카테고리를 선택했을 때 이전 데이터를 지우고 새로운 데이터를 가져오기 위해 사용됩니다.
4. 전체 코드 동작 흐름
(1) fetchVideos 호출
컴포넌트에서 dispatch(fetchVideos({ categoryId, pageToken }))를 호출
(2) API 요청 시작
fetchVideos.pending 상태로 전환, 로딩 중임을 표시
(3) API 요청 성공
fetchVideos.fulfilled로 상태 업데이트, videoList에 새 데이터 추가
(4) API 요청 실패
fetchVideos.rejected로 에러 메시지를 저장
5. Redux 상태의 이점
1) 중앙 집중식 상태 관리
비디오 데이터, 로딩 상태, 에러 메시지를 한 곳에서 관리하여 코드 가독성과 유지보수성을 높였습니다.
2) 비동기 작업 간소화
createAsyncThunk를 활용해 비동기 작업과 상태 관리를 분리. 코드의 복잡도가 줄어들고 가독성이 향상되었습니다.
3) 재사용 가능한 구조
fetchVideos와 MainReducer는 다른 API 요청과 상태 관리에도 쉽게 확장 가능합니다.
이처럼 Redux Toolkit을 활용한 메인화면 모습을 확인해봤는데요.
Redux Toolkit은 비디오 데이터를 효율적으로 관리하는 방법을 보여줍니다.
createAsyncThunk를 통해 비동기 작업을 간단하게 정의하고, createSlice를 통해 상태와 리듀서를 통합적으로 관리할 수 있습니다.
이를 통해 더 간결하고 유지보수 가능한 코드를 작성할 수 있으니 적용해보세요 ~!
Redux Toolkit 자세한 사항은 아래 사이트들을 참고하시면 좋을 것 같습니다.
Getting Started | Redux Toolkit
redux-toolkit.js.org
React와 Redux를 활용한 비동기 작업 관리는 아래 포스터에 들어가면 자세히 확인할 수 있습니다.
[30] React와 Redux를 활용한 비동기 작업 관리
React와 Redux를 활용한 비동기 작업 관리는 Redux Toolkit과 함께 사용하면 더욱 간편해집니다. 비동기 작업 관리의 핵심은 데이터를 비동기적으로 가져오는 작업(API 호출 등)을 관리하고, 이를 Redux
uplifted.tistory.com