Redux Saga를 이용해 비동기적으로 api를 호출할 때 요청에 대한 5가지 상태 ( 요청 시작, 로딩 중, 요청 성공, 요청 실패, 로딩 끝 ) 관리를 다루는 글입니다.
// lib/api.js
import axios from "axios";
export const getCategories = () =>
export const getStores = () => axios.get('http://localhost:4000/stores');
json-server를 이용하여 만든 json 파일 🔗 json-server 사용
// 액션 타입 정의
const START_LOADING = "loading/START_LOADING";
const FINISH_LOADING = "loading/FINISH_LOADING";
// 액션 생성 함수
export const startLoading = (requestType) => ({
type: START_LOADING,
requestType,
});
export const finishLoding = (requestType) => ({
type: FINISH_LOADING,
requestType,
});
// 초기화
const initialStete = {};
// 리듀서 작성
function loading(state = initialStete, action) {
switch (action.type) {
case START_LOADING:
return {
...state,
// action.payload = requestType
// 즉, requestTtype: true
[action.payload]: true,
};
case FINISH_LOADING:
return {
...state,
[action.payload]: false,
};
default:
return state;
}
}
export default loading;
// reducers/data.js
import * as api from "../lib/api";
import { call, put, takeLatest } from "redux-saga/effects";
// loading 객체 생성 함수 가져오기
import { finishLoding, startLoading } from "./loading";
// 액션 타입 정의
const GET_STORES = "data/GET_STORES";
const GET_STORES_SUCCESS = "data/GET_STORES_SUCCESS";
const GET_STORES_FAILURE = "data/GET_STORES_FAILURE";
// 액션 생성 함수
export const getStores = () => ({ type: GET_STORES });
// SAGA 작성
function* getStoresSaga() {
yield put(startLoading(GET_STORES));
try {
const stores = yield call(api.getStores);
yield put({
type: GET_STORES_SUCCESS,
payload: stores.data,
});
} catch (e) {
yield put({
type: GET_STORES_FAILURE,
payload: e,
error: true,
});
}
yield put(finishLoding(GET_STORES));
}
// SAGA 통합
export function* dataSaga() {
yield takeLatest(GET_STORES, getStoresSaga);
}
// 초기값 설정
const initialStete = {
stores: null,
};
// 리듀서 작성
function data(state = initialStete, action) {
switch (action.type) {
case GET_STORES_SUCCESS:
return {
...state,
stores: action.payload,
};
case GET_STORES_FAILURE:
default:
return state;
}
}
export default data;
// components/allStores.js
// 개인적으로 사이드 프로젝트에서 사용하는 컴포넌트 입니다.
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { getStores } from '../reducers/data';
const AllStores = () => {
const stores = useSelector((state) => state.data.stores);
const loadingStores = useSelector((state) => state.data.GET_STORES);
const storesDispatch = useDispatch();
useEffect(() => {
storesDispatch(getStores());
}, [getStores, storesDispatch]);
return (
<div className="allStores">
{loadingStores && '로딩 중'}
{!loadingStores &&
....
))}
</div>
);
};
export default React.memo(AllStores);
useSelector Hooks를 사용하여 store(리덕스)에 접근, stores와 loading 상태를 저장.
useDispatch를 이용해 네트워크 요청 action getStores dispatch
&& 연산자를 loadingStores의 상태에 따라 하나의 상태만을 위한 렌더링