3-7-정규화된-데이터-업데이트

앞의 블로그 예제를 다시 사용하자. 먼저, 포스트에 새 댓글을 추가하는 예시를 보자.

일반적인 접근

간단한 병합

기존 상태 액션의 컨텐츠에 병합 하는 것이다. 이 경우에 얕은 복사가 아닌 깊은 재귀병합을 해야한다. Lodash의 merge함수는 이를 처리할 수 있다.

import merge from "lodash/merge";

function commentsById(state = {}, action) {
    switch(action.type) {
        default : {
           if(action.entities && action.entities.comments) {
               return merge({}, state, action.entities.comments.byId);
           }
           return state;
        }
    }
}

이케하면 리듀서는 최소 작업량을 필요로한다. 하지만 action creator는 액션을 디스패치 하기 전에 적당한 형태로 구성하기 위해 2배의 작업을 필요로 한다.

슬라이스 리듀서 구성

슬라이스 리듀서가 중첩된 트리가 있다면 각 슬라이스 리듀서는 액션에 적절히 응답하는 법을 알고 있어야 한다. 일단 포스트 새 댓글을 추가하는 예시를 계속 사용한다고 하자

  • 해당 포스트 객체에 댓글 ID추가

  • 해당 키를 ID로 하는 새로운 댓글 객체 추가

  • 전체 댓글 ID 리스트에 댓글의 ID 추가

이 조각들을 맞춰보자

// actions.js

function addComment(postId, commentText) {
  const commentId = generateId("comment");

  return {
    type: 'ADD_COMMENT',
    payload: {
      postId,
      commentId,
      commentText
    }
  }
}

// reducers/post.js

// 해당 post 객체에 댓글 id 추가하기
function addComment(state, action) {
  const {payload} = action;
  const {postId, commentId} = payload;

  const post = state[postId];

  return {
    ...state,
    [postId]: {
      ...post,
      comments: post.comments.concat(commentId)
    }
  }
}

function postsById(state = {}, action) {
  switch(action.type) {
    case "ADD_COMMENT": return addComment(state, action);
    default: return state;
  }
}

function allPosts(state = [], action) {

}

const postsReducer = combineReducers({
  byId: postsById,
  allIds: allPosts
})
// reducers/comment.js

function addCommentEntry(state, action) {
  const {payload} = action;
  const {commentId, commentText} = payload;

  const comment = {id: commentId, text: commentText};

  return {
    ...state,
    [commentId]: comment
  }
}

function commentsById(state = {}, action) {
  switch(action.type) {
    case "ADD_COMMENT": return addCommentEntry(state, action);
    default: return state;
  }
}

function addCommentId(state, action) {
    const {payload} = action;
    const {commentId} = payload;
    // 새 댓글 ID를 전체 ID 리스트에 추가
    return state.concat(commentId);
}

function allComments(state = [], action) {
    switch(action.type) {
        case "ADD_COMMENT" : return addCommentId(state, action);
        default : return state;
    }
}

const commentsReducer = combineReducers({
    byId : commentsById,
    allIds : allComments
});

이 예제는 슬라이스 리듀서와 케이스 리듀서를 어떻게 맞추고 있는지 보여주고 있다. 여기에서 위임에 유의하자. postsById 슬라이스 리듀서는 새로운 댓글 ID를 적절한 포스트에 삽입하는 작업을 addComment에 위임한다. 반면 commentsById와 allComments 슬라이스 리듀서는 댓글 룩업테이블과 전체 댓글 ID를 적절히 업데이트하는 자신의 케이스 리듀서를 가지고 있다.

Last updated

Was this helpful?