Redux-Cunk 흐름의 복습
- 기존의 파일에서 리덕스 청크로 서버와 통신하는 부분을 다시 로직을 짜면서 리덕스 청크의 흐름에 대해 복습하기로 했다.
- 리듀서 부분
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
import axios from 'axios';
const meetingsSlice = createSlice({
name: 'meetingList',
initialState,
reducer:{},
extraReducers(builder) {
builder
.addCase(__getMeetings.pending, (state, action) => {
state.isLoading = true;
state.isError = false;
})
.addCase(__getMeetings.fulfilled, (state, action) => {
state.isLoading = false;
state.isError = false;
state.meetings = action.payload;
})
.addCase(__getMeetings.rejected, (state, action) => {
state.isLoading = false;
state.isError = true;
state.error = action.payload;
export default meetingsSlice.reducer;
- 위 코드의 흐름은 다음과 같다.
- createAsyncThunk 함수를 이용해 비동기로 데이터를 받아오는 작업을 수행하는 액션 함수를 생성한다.
- createSlice 함수를 사용하여 slice(리듀서, 액션 생성자 등)를 만든다.
- extraReducers() 메서드를 이용하여 해당 slice에 비동기 액션들의 성공, 실패, 진행 상태 등의 케이스를 정의한다.
- 비동기 액션들이 성공/실패하는 경우 각각 추가적인 로직(process)을 수행하고, 이를 리듀서 내에서 반영한다.
- 컴포넌트 부분
import React, { useEffect } from 'react';
import { __getMeetings } from '../redux/config/modules/meetingsSlice';
import { useDispatch, useSelector } from 'react-redux';
function List() {
const dispatch = useDispatch();
useEffect(() => {
dispatch(__getMeetings());
}, [dispatch]);
const { isLoading, error, meetings } = useSelector((state) => {
return state.meetingsSlice;
});
if (isLoading) {
return <div>로딩 중입니다</div>;
}
if (error) {
return <div>에러 발생!</div>;
}
- 위 코드의 흐름은 다음과 같다
- useSelector Hook을 사용하여 Redux store에서 state를 가져온다.
상태(state) 변화에 따라 변경된 컴포넌트 뷰(View)를 반환한다.
- 위 코드에서 조금 더 자세히 본다면, getMeetings는 서버로부터 data를 읽어와 성공/실패 여부에 따른 fulfilled/rejected action을 dispatch한다.
Action에 대한 적절한 state 변화와 함께 대응하는 리듀서 Reducer를 제공한다.
- List() component에서 useDispatch hook으로 getMeetings() function을 호출하면, pending -> fulfilled or rejected 순서로 액션을 발생시키며 이에 대응하여 state가 변경된다.
- 결과적으로 해당 작업에 대한 진행/완료 여부는 isLoading, error 등으로 나타내고, 그에 따라 알맞은 View가 나타나게 된다.
- 이렇게 Redux에서 지정한 선언적 프로그래밍 패턴을 활용하면 비동기 처리 작업과 그 모니터링을 용이하게 할 수 있다.
전 버전으로 쓰지 않기
- extraReducers를 배울 때의 방식으로 쓰니 오류가 발생했다.
export const todoSlice = createSlice({
name: 'todos',
initialState,
reducers: {},
extraReducers: {
[__getTodos.pending]: (state, action) => {
state.isLoading = true;
state.isError = false;
},
[__getTodos.fulfilled]: (state, action) => {
state.isLoading = false;
state.isError = false;
state.todos = action.payload;
},
[__getTodos.rejected]: (state, action) => {
state.isLoading = false;
state.isError = true;
state.error = action.payload;
},
},
});
- 위의 방식은 쓰이지 않으니 바로 앞서 제시한 방식으로 쓸 것을 유념하자.