리액트 - redux-thunk로 Promise 다루기(createPromiseThunk)로 리팩토링

정영찬·2022년 4월 23일
0

리액트

목록 보기
63/79
post-custom-banner

getPosts와 getPost thunk 생성함수를 좀더 리팩토링 해보자.

이전에 작성한 asyncUtils.js 파일에 createPromiseThunk 함수를 작성한다.

파라미터

  • type : 액션 타입의 앞부분 getPosts, getPost
  • promiseCreator : postsAPI.getPostById()와 같은 promise 생성함수

SUCCESS, ERROR 의 액션 타입을 비구조화 활당으로 선언한다.

const [SUCCESS, ERROR] = [`${type}_SUCCESS`,`${type}_ERROR`];

thunkCreator : 파라미터값을 받아와서 dispatch하는 비동기 함수

const thunkCreator = param => async dispatch => {
        dispatch({type})
        try {
            const payload = await promiseCreator(param);
            dispatch({
                type:SUCCESS,
                payload
            })
        } catch(e){
            dispatch({
                type:ERROR,
                payload: e,
                error: true,
            })
        }
    }

dispatch호출을 알리고 SUCCESS의 경우 try 내부의 dispatch가, 실패의 경우에는 catch 내부의 dispatch가 호출된다.

전체 내용

export const createPromiseThunk = (type, promiseCreator) => {
    const [SUCCESS, ERROR] = [`${type}_SUCCESS`,`${type}_ERROR`];

    const thunkCreator = param => async dispatch => {
        dispatch({type})
        try {
            const payload = await promiseCreator(param);
            dispatch({
                type:SUCCESS,
                payload
            })
        } catch(e){
            dispatch({
                type:ERROR,
                payload: e,
                error: true,
            })
        }
    }
    return thunkCreator
}

payload?

FSA규칙에 따라서 모든 액션의 추가적인 값을 payload라는 이름으로 통일한다. 굳이 이렇게 해야할 필요는 없지만 규칙을 지켜주면 좀더 가시성이 좋아진다.

이 함수를 통해서 이전에 작성했던 getPosts 와 getPost를 단 한줄 씩으로 요약이 가능해진다.

export const getPosts = createPromiseThunk(GET_POSTS, postsAPI.getPosts)

export const getPost = createPromiseThunk(GET_POST,postsAPI.getPostById)

promise 호출로 return 된 내용을 payload 라고 선언했기 때문에! 리듀서에서 상태 변경값을 수정해야한다.

export default function posts(state, action) {
  switch (action.type) {
    case GET_POSTS:
      return {
        ...state,
        posts: reducerUtils.loading(state.posts.data)
      };
    case GET_POSTS_SUCCESS:
      return {
        ...state,
        posts: reducerUtils.success(action.payload)
      };
    case GET_POSTS_ERROR:
      return {
        ...state,
        posts: reducerUtils.error(action.payload)
      };
    case GET_POST:
      return {
        ...state,
        post: reducerUtils.loading(state.post.data)
      };
    case GET_POST_SUCCESS:
      return {
        ...state,
        post: reducerUtils.success(action.payload)
      };
    case GET_POST_ERROR:
      return {
        ...state,
        post: reducerUtils.error(action.payload)
      };

    default:
      return state;
  }
}

좀더 일관된 모습이긴 하지만... 비슷한 모습이 아직도 보인다는 것은 이 내용을 재활용 가능한 util함수를 만들 수 있다는 소리다.

다음에는 여기서 좀더 리팩토링을 진행해보자.

profile
개발자 꿈나무
post-custom-banner

0개의 댓글