#36.TIL | Immer

Seongjae Hwang·2022년 2월 7일
0

Immer를 사용하지 않고 불변성 유지하며 업데이트 하기

기존 리액트에서 배열이나 객체를 업데이트 해야 할때는 직접 원본을 수정하면 안되고, 아래와 같이 불변성을 지켜주면서 업데이트를 해주어야 했다.

const object = {
  a: 1,
  b: 2,
  c: 3,
  d: 4,
};

const copyObject = {
  ...object,
  b: 100
};

배열도 마찬가지로 push, splice 등 원본을 바꾸는 메서드가 아닌 concat, filter, map 등 새로운 배열을 반환하는 메서드를 사용하였다. 물론, spread연산자를 활용하여 불변성을 지켜가며 새로운 데이터를 생성할 수 있었지만, 복잡한 구조의 객체를 업데이트해야 한다고 하면, 코드가 매우 복잡해지게 된다.

const state = {
  posts: [
    {
      id: 1,
      title: '제목입니다.',
      body: '내용입니다.',
      comments: [
        {
          id: 1,
          text: '와 정말 잘 읽었습니다.'
        }
      ]
    },
    {
      id: 2,
      title: '제목입니다.',
      body: '내용입니다.',
      comments: [
        {
          id: 2,
          text: '또 다른 댓글 어쩌고 저쩌고'
        }
      ]
    }
  ],
  selectedId: 1
};

위와 같이 복잡한 형태의 데이터 객체에서 id값이 1인 post에 댓글을 추가하는 업데이트를 해준다고 하면, 아래와 같이 업데이트를 해줘야 한다.

const nextState = {
  ...state,
  posts: state.posts.map(post =>
    post.id === 1
      ? {
          ...post,
          comments: post.comments.concat({
            id: 3,
            text: '새로운 댓글'
          })
        }
      : post
  )
};

코드의 구조가 복잡해지면서 가독성도 떨어진다. Immer라는 라이브러리를 사용하면 아래와 같이 데이터의 상태를 업데이트 할때, 불변성을 신경쓰지 않으면서 구현할 수 있다.

const nextState = produce(state, draft => {
  const post = draft.posts.find(post => post.id === 1);
  post.comments.push({
    id: 3,
    text: '와 정말 쉽다!'
  });
});

(출처: 벨로퍼트와 함께하는 리액트)

Immer 사용법

import produce from 'immer'

const originalState = [
  {
    id: 1,
    todo: '일번 입니다.',
    checked: true,
  },
  {
  	id: 2,
    todo: '이번 입니다.',
    checked: false,
  }
];

const newState = produce(originalState, draft => {
  // id가 2인 항목의 checked 값을 true로 설정
  const todo = draft.find(t => t.id === 2); //id로 항목 찾기
  todo.checked = true;
  	//혹은 draft[1].checked = true;
  
  // 배열에 새로운 데이터 추가
  draft.push({
  	id: 3,
    todo: '삼번 입니다.'
    checked: false,
  });
  
  // id = 1인 항목을 제거하기
  draft.splice(draft.findIndex(t => t.id === 1), 1);
});

첫 번째 파라미터는 수정하고 싶은 상태이고, 두 번째 파라미터는 상태를 어떻게 업데이트할지 정의하는 함수이다. 두 번째 파라미터로 전달되는 함수 내부에서 원하는 값을 변경하면, produce 함수가 불변성 유지를 대신해 주면서 새로운 상태를 생성해 주게 된다.


위의 예시는 실제로 적용한 코드중 state를 업데이트하는 과정에서 객체의 값을 추가하는 부분인데, 단순한 데이터 형식이다 보니 굳이 사용할 필요는 없었지만, 학습을 위해 한번 적용시켜 보았다.
첫번째 사진에서는 state의 불변성을 지키기 위해 spread연산자를 활용하여 업데이트하였지만, 아래는 value와 name을 구조분해할당을 통해 선언하고, immer를 적용하였다.

profile
Always Awake

0개의 댓글