(TIL 17일차) React (6)

pks787·2020년 2월 13일
0

TIL(Today I Learned)

목록 보기
10/43

Immer 라이브러리

  • 기존의 배열이나 객체를 변경할 때 직접 수정이 아닌 불변성을 지켜주면서 변경함
  • Ex) push,splice 사용 X, concat,filter,map O
  • 그러나 배열이나 아래와 같이 객체의 구조가 복잡해지면 원하는 요소에 접근하기 힘듦
const state = {
  posts: [
    {
      id: 1,
      title: '제목입니다.',
      body: '내용입니다.',
      comments: [
        {
          id: 1,
          text: '와 정말 잘 읽었습니다.'
        }
      ]
    },
    {
      id: 2,
      title: '제목입니다.',
      body: '내용입니다.',
      comments: [
        {
          id: 2,
          text: '또 다른 댓글 어쩌고 저쩌고'
        }
      ]
    }
  ],
  selectedId: 1
};
// 원하는 요소 접근하기 힘듦(코드 복잡도 올라감)
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가 불변성 관리 담당

Immer 사용법

  1. immer 라이브러리 설치
npm i immer --save
  1. 보통 produce라는 이름으로 import 해줌
import produce from 'immer';
  1. produce 함수 첫번째 파라미터는 수정하고 싶은 상태, 두번째 파라미터는 어떻게 업데이트하고 싶은지 정의 하는 함수 작성
const state = {
  number: 1,
  dontChangeMe: 2
};

const nextState = produce(state, draft => {
  draft.number += 1;
});

console.log(nextState);
// { number: 2, dontChangeMe: 2 }

리듀서에서 Immer 사용하기

function reducer(state, action) {
  switch (action.type) {
    case 'CREATE_USER':
      return produce(state, draft => {
        draft.users.push(action.user);
      });
    case 'TOGGLE_USER':
      return produce(state, draft => {
        const user = draft.users.find(user => user.id === action.id);
        user.active = !user.active;
      });
    case 'REMOVE_USER':
      return produce(state, draft => {
        const index = draft.users.findIndex(user => user.id === action.id);
        draft.users.splice(index, 1);
      });
    default:
      return state;
  }
}

기본 함수형 컴포넌트에서 Immer 사용하기

const todo = {
  text: 'Hello',
  done: false
};

const updater = produce(draft => {
  draft.done = !draft.done;
});

const nextTodo = updater(todo);

console.log(nextTodo);
// { text: 'Hello', done: true }
// 아래와 같은 의미
const [todo, setTodo] = useState({
  text: 'Hello',
  done: false
});

const onClick = useCallback(() => {
  setTodo(
    produce(draft => {
      draft.done = !draft.done;
    })
  );
}, []);
  • 위와 같이 첫번째 파라미터 없이 바로 업데이트 함수만 있으면 useState 업데이트 함수를 사용 할 때

사용 예외의 경우

  • Immer를 사용해서 간단해지는 업데이트가 있고, 오히려 길어지는 코드도 존재
  • 객체의 구조가 복잡하지 않고 간단한 경우 concat이나 filter를 사용하는 것이 더 유리

정리

  • 성능적으로는 Immer를 안 쓰는 것이 더 빠름
  • 불변성을 유지하기 복잡한 상황이 오면 사용하도록 권장
  • 무조건 사용한다는 생각은 버리기

profile
Front End. Dev

0개의 댓글