불변성 관리
리액트에서 배열이나 객체를 업데이트 해야할 때에는 직접 수정하면 안되고 불변성을 지켜주면서 업데이트를 해주어야 한다.
배열도 마찬가지로 push
, splice
등의 함수를 사용하거나 n번째 항목을 직접 수정하면 안되고 concat
, filter
, map
등의 함수를 사용해야 한다.
immer 를 사용하면 불변성을 해치는 코드를 작성해도 대신 불변성을 유지 해준다.
🚨 Immer는 편하지만 성능적으로 Immer를 사용하지 않은 코드가 조금 더 빠르다. 자주 사용하면 오히려 사용하지 않았을 때 보다 속도가 더 느려진다고 한다. 따라서 불변성을 유지하기에 데이터의 구조가 복잡해지는 상황에 사용하는 것을 권장하고, immer 대신 ...
스프레드 연산자를 사용하는 것을 추천한다.
예시
// 값을 직접 수정
const object = {
a: 1,
b: 2
};
object.b = 3;
// 불변성을 유지하며 수정하기
const object = {
a: 1,
b: 2
};
const nextObject = {
...object,
b: 3
};
Immer 사용법
설치
$ yarn add immer
불러오기
Immer 라이브러리를 사용할 때에는 코드의 상단에서 immer 를 불러오는데, 보통 produce
라는 이름으로 불러온다.
import produce from 'immer';
사용법
produce 함수를 사용할 땐 첫번째 파라미터에는 수정하고 싶은 상태, 두번째 파라미터에는 어떻게 업데이트 할 지 정의하는 함수를 넣어준다.
두번째 파라미터에 넣는 함수에서는 불변성에 대해서 신경쓰지 않고 그냥 업데이트 하면 알아서 처리해준다.
const state = {
number: 1,
dontChangeMe: 2
};
const nextState = produce(state, draft => {
draft.number += 1;
});
console.log(nextState);
// { number: 2, dontChangeMe: 2 }
함수형 업데이트
produce 함수에 두 개의 파라미터를 넣게 된다면 첫번째 파라미터에 넣은 상태를 불변성을 유지하면서 새로운 상태를 만들어준다.
만약에 첫번째 파라미터를 생략하고 바로 업데이트 함수를 넣어주게 된다면, 반환값은 새로운 상태가 아닌 상태를 업데이트 해주는 함수가 된다.
const todo = {
text: 'Hello',
done: false
};
const updater = produce(draft => { // state 가 없는 업데이트 함수 형태
draft.done = !draft.done;
});
const nextTodo = updater(todo);
console.log(nextTodo);
// { text: 'Hello', done: true }
결국 produce 가 반환하는 것이 업데이트 함수가 되어서 useState 의 함수를 사용할 때 다음과 같이 구현할 수 있다.
const [todo, setTodo] = useState({
text: 'Hello',
done: false
});
const onClick = useCallback(() => {
setTodo(
produce(draft => {
draft.done = !draft.done;
})
);
}, []);