리듀서에서 액션타입에 따른 상태변화의 내용이 거의 비슷한 같은 내용으로 반복되는 것이 보이는데, 이를 handleAsyncActions 라는 유틸함수를 만들어서 리팩토링을 진행할 것이다
파라미터
type : 액션 타입
key : 변경된 상태값을 담아놓은 변수 이름 (posts, post)
리듀서의 내용을 대신하기 때문에 리듀서와 비슷하게 작성한다고 생각하면 수월하다.
타입의 뒷내용을 비구조화 할당으로 분리해서 선언하고, 리듀서의 형식대로 작성하되, 리턴으로 변경되는 데이터를 저장한 변수를 파라미터로 받아온 key 값으로 변경하면 끝이다.
export const handleAsyncActions = (type, key) => {
const [SUCCESS, ERROR] = [`${type}_SUCCESS`, `${type}_ERROR`];
return (state, action) => {
switch (action.type) {
case type:
return {
...state,
[key]: reducerUtils.loading(state.posts.data),
};
case SUCCESS:
return {
...state,
[key]: reducerUtils.success(action.payload)
};
case ERROR:
return{
...state,
[key]: reducerUtils.error(action.payload)
}
default:
return state;
}
};
};
이 함수를 사용하여 이전에 작성한 posts 모듈에서의 리듀서를 리팩토링 할 수 있다.
const getPostsReducer = handleAsyncActions(GET_POSTS, 'posts')
const getPostReducer = handleAsyncActions(GET_POST, 'post')
이 두가지 변수를 사용하면
posts 리듀서를
export default function posts(state, action) {
switch (action.type) {
case GET_POSTS:
case GET_POSTS_SUCCESS:
case GET_POSTS_ERROR:
return getPostsReducer(state,action)
case GET_POST:
case GET_POST_SUCCESS:
case GET_POST_ERROR:
return getPostReducer(state,action)
default:
return state;
}
}
이렇게 변경이 가능해진다. getPosts의 경우에 해당하는 액션타입과 getPost에 해당하는 액션타입을 하나로 묶어서 리턴 값으로 유틸함수를 사용한 변수를 지정하면 된다.
현재 posts.js 모듈의 내용은 훨신 더 짧아졌다.
import * as postsAPI from "../api/posts";
import { createPromiseThunk, handleAsyncActions, reducerUtils } from "../lib/asyncUtils";
const GET_POSTS = "GET_POSTS";
const GET_POSTS_SUCCESS = "GET_POSTS_SUCCESS";
const GET_POSTS_ERROR = "GET_POSTS_ERROR";
const GET_POST = "GET_POST";
const GET_POST_SUCCESS = "GET_POST_SUCCESS";
const GET_POST_ERROR = "GET_POST_ERROR";
/*thunk 생성 함수*/
export const getPosts = createPromiseThunk(GET_POSTS, postsAPI.getPosts)
export const getPost = createPromiseThunk(GET_POST,postsAPI.getPostById)
const initialState = {
posts: reducerUtils.initial(),
post: reducerUtils.initial()
};
const getPostsReducer = handleAsyncActions(GET_POSTS, 'posts')
const getPostReducer = handleAsyncActions(GET_POST, 'post')
export default function posts(state, action) {
switch (action.type) {
case GET_POSTS:
case GET_POSTS_SUCCESS:
case GET_POSTS_ERROR:
return getPostsReducer(state,action)
case GET_POST:
case GET_POST_SUCCESS:
case GET_POST_ERROR:
return getPostReducer(state,action)
default:
return state;
}
}
야호