[React] Redux-Thunk로 비동기적으로 action dispatch하기

박세화·2023년 7월 31일

React JS

목록 보기
18/22

📌 Redux-Thunk란?

data fetching을 위하여 흔히 사용되는 redux middleware 이다. 이 미들웨어를 사용하여 액션 객체가 아닌 함수를 dispatch할 수 있다.

thunk는 프로그래밍 용어로서는 "미뤄진 작업을 처리하는 코드 조각"을 뜻한다. 함수를 작성하여 코드가 일정 시간 후에 실행되도록 만들 수 있다. Redux에 국한하여 뜻을 정의하자면, 이는 Redux내의 dispatch, getState와 소통할 수 있는 함수를 작성하는 방법을 말한다.

우선 thunk를 사용하기 위해선 redux-thunk 미들웨어를 redux store에 추가해야한다.

✋ Thunk function 작성법
두 가지 매개변수를 받는다 => Redux store의 dispatch와 getState 메소드
Thunk function은 직접적으로 불리지 않고 dispatch를 통해서 호출된다.

상단의 shop을 누르면 해당 페이지가 뜬다. 본래 코드는 누르자마자 데이터들이 바로 뜨도록 구현되지만, redux-thunk를 사용함으로써 product data들을 가져오는 것을 잠시 딜레이하고 그 시간 동안 로딩 아이콘이 돌아가도록 할 것이다.


▶ redux-thunk 작성

categories.types.js

export const CATEGOREIS_ACTION_TYPES = {
    //SET_CATEGORIES: 'category/SET_CATEGORIES',
    FETCH_CATEGORIES_START: 'category/FETCH_CATEGORIES_START',
    FETCH_CATEGORIES_SUCCESS: 'category/FETCH_CATEGORIES_SUCCESS',
    FETCH_CATEGORIES_FAILED: 'category/FETCH_CATEGORIES_FAILED',
}
  • action type이 세 개로 갈라졌다. category item들을 가져오기 시작할 때의 액션, 성공했을 때의 액션, 실패 시의 액션

categories.reducer.js

import { CATEGOREIS_ACTION_TYPES } from './category.types'

export const CATEGORIES_INITIAL_STATE = {
  categories: [],
  isLoading: false,
  error: null,
};

export const categoriesReducer = (
  state = CATEGORIES_INITIAL_STATE,
  action = {}
) => {
  const { type, payload } = action;

  switch (type) {
    case CATEGOREIS_ACTION_TYPES.FETCH_CATEGORIES_START:
      return { ...state, isLoading: true };
    case CATEGOREIS_ACTION_TYPES.FETCH_CATEGORIES_SUCCESS:
      return { ...state, categories: payload, isLoading: false };
    case CATEGOREIS_ACTION_TYPES.FETCH_CATEGORIES_FAILED:
      return { ...state, error: payload, isLoading: false };
    default:
      return state;
  }
};
  • INITIAL_STATE에는 원래 category 배열만이 있었지만, isLoadingerror가 추가되었다. isLoading의 값으로 로딩 아이콘의 렌더링을 제어할 것이다.

categories.action.js

export const fetchCategoriesStart = () =>
  createAction(CATEGOREIS_ACTION_TYPES.FETCH_CATEGORIES_START);

export const fetchCategoriesSucess = (categoriesArray) =>
  createAction(
    CATEGOREIS_ACTION_TYPES.FETCH_CATEGORIES_SUCCESS,
    categoriesArray
  );

export const fetchCategoriesFailed = (error) =>
  createAction(CATEGOREIS_ACTION_TYPES.FETCH_CATEGORIES_FAILED, error);

//async func
export const fetchCategoriesAsync = () => {
  return async (dispatch) => {
    dispatch(fetchCategoriesStart());

    try {
      const categoriesArray = await getCategoriesAndDocuments("categories");
      dispatch(fetchCategoriesSucess(categoriesArray));
    } catch (error) {
      dispatch(fetchCategoriesFailed(error));
    }
  };
};
  • 맨 밑에 있는 fetchCategoriesAsync 함수가 thunk function이다.
    fetchCategoriesStart를 dispatch하는 action function을 반환한다.
  • 그 이후, categoriesArray를 불러오는 함수를 비동기적으로 처리한다. 데이터를 받은 후, fetchCategoriesSucess 를 dispatch한다.
  • 만약 데이터를 불러오는 과정에서 에러가 생기면 fetchCategoriesFailed 함수를 부른다.

▶이제 thunk function을 외부에서 불러오자

shop.component.js

const Shop = () => {
  const dispatch = useDispatch();
  
  useEffect(()=>{
      dispatch(fetchCategoriesAsync());
  },[])

  return (
      <Routes>
        <Route index element={<CategoriesPreview />} />
        <Route path=":category" element={<Category />} />
      </Routes>
  );
};

export default Shop;
  • shop 페이지(위의 캡쳐화면)이 최초로 렌더링 될 때 fetchCategoriesAsync를 dispatch한다.
  • 해당 함수 내에선 가장 먼저 fetchCategoriesStart 를 dispatch하기 때문에 isLoading 상태값이 true로 바뀐다.

categories-preview.component.js

const CategoriesPreview = () => {
  const categoriesMap = useSelector(selectCategoriesMap);
  const isLoading = useSelector(selectCategoriesIsLoading);

  return (
    <div className="categories-preview-container">
      {isLoading ? (
        <Spinner />
      ) : (
        Object.keys(categoriesMap).map((title) => {
          const products = categoriesMap[title];
          return (
            <CategoryPreview key={title} title={title} products={products} />
          );
        })
      )}
    </div>
  );
};

export default CategoriesPreview;
  • isLoading이 true인 동안은 스피너 컴포넌트가 렌더링되고, categoriesArray가 완성이 되어 isLoading이 다시 false로 바뀌면 제품 컴포넌트들이 보여진다.

공식문서

1개의 댓글

comment-user-thumbnail
2023년 7월 31일

잘 읽었습니다. 좋은 정보 감사드립니다.

답글 달기