getPosts와 getPost thunk 생성함수를 좀더 리팩토링 해보자.
이전에 작성한 asyncUtils.js 파일에 createPromiseThunk 함수를 작성한다.
파라미터
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함수를 만들 수 있다는 소리다.
다음에는 여기서 좀더 리팩토링을 진행해보자.