Component
를 리렌더링하고 최적화 할때, 불변성이 유지되어야 함
const obj = {
a: 'hello',
b: 12345
};
다음과 같은 객체에서
object.b = 678910;
이런식으로 바꾸게 되면 불변성이 깨짐
따라서 만약에 678910
이 b
에 들어가는 객체를 만들고 싶으면, 새로운 객체를 만들어서 값을 새롭게 넣어줘야 함
const obj = {
a: 'hello',
b: 12345
};
const nextObject = {
...object,
b: 678910
};
이렇게 해야 obj
의 값이 변경되지 않아서 좋음
배열같은 경우도 값을 삽입하는 push, 값을 빼는 splice를 사용할 것이 아니라 filter나 map, concat 등으로 새롭게 배열을 만들어내는 것으로 불변성을 지킴
단, 이를 코드로 구현하는게 생각보다 까다롭고 복잡한 것이 문제
아니, 그렇게 어렵지 않다고 하더라도 코드의 가독성이 많이 떨어짐
이럴때 사용하는 것이 바로 immer
immer
라이브러리는 불변성을 해치는 코드도 대신 불변성을 유지해주는 든든한 역할을 수행함
yarn add immer
다음 명령어를 터미널에 입력하여, immer
라이브러리를 설치함
파일에선 import
할 때, import immer
가 아닌 produce
를 사용함
이유는 확실치 않지만, 불변성을 지키기위해 자체적으로 새롭게 객체를 만들어내는 점 때문에 produce
라는 이름을 지은게 아닌가 생각함
import produce from 'immer';
위와 같이 선언
const a = {
number: 1,
numberr: 2,
};
const b = produce(a, draft => {draft.number += 1});
console.log(a);
console.log(b);
// 결과 a = {number:1, numberr:2}, b = {number:2, numberr:2}
immer
의 produce
를 사용하면 a
에서 조금 바뀐 b
를 새로 만들어냄
이로써 불변성을 지켰다고 볼 수 있음
produce(a, draft)
에서 a
는 새롭게 만들어질 b
에 복사할 대상이고, draft
는 실제로 복사된 값임
즉, draft
는 처음엔 a
와 값이 완벽히 동일한데, 그대로 아무것도 건드리지 않으면, b
는 a
와 똑같은 값을 가지게 됨
하지만, draft => {draft.number += 1}
처럼 안의 내용을 바꿔주게 되면 b
는 a
와 비슷하지만 내부가 바뀜 물론 그 전의 a
, b
가 값만 같을 뿐이지 같은 객체라곤 볼 수 없지만, 그래도 값이 같았는데 draft
에 의해 아예 값이 다른 새로운 b
를 만들 수 있음
immer
를 쓸 경우는 concat
대신 push
, map
대신 find
를 써서 해당 객체를 찾아내서 값을 변경하고, filter
대신 findIndex
를 로 찾아내서 해당 객체로부터 splice
를 통해 제외시킴
immer
의 경우, 꼭 불변성을 위해 반드시 사용해야 하는 것은 아님
immer
를 굳이 사용할 때보다 기존의 코드가 불변성도 지키면서 간단할 경우, 사용하지 않아도 됨
예를 들어,
users: state.users.concat(user);
라는 코드가 있다고 치면, 이를 immer로 구현할 경우
users: produce(state, draft => {
draft.users.push(user)
});
이런식이 됨. 이는 굳이 1줄로도 불변성을 지킬 수 있는 것을 굳이 3줄로 늘여써서 오히려 더 이해가 힘듦
immer
를 업데이트로 활용할 수 있는 방법
const updater = produce(draft => ~~~);
원래는 draft에 복사할 값인 state를 넣어줘야 하는데, 그냥 이렇게 draft만 넣는 경우가 있음
예를 들어,
const a = {
b: 'hi',
c: true
};
가 있을 경우, 이를 업데이트 해주는 방법이 존재
const updater = produce(draft => {draft.c = !draft.c});
const next = updater(a);
이런식으로 해주게 되면 next
는
{b:'hi', c:false}
가 됨 이를 useState
에 활용하면 좋음
useState
에서는 함수형으로 useCallback
안에서 값을 바꿔주게 되면 굳이 두번째 매개변수에 []
안에 사용된 객체를 넣어주지 않아도 되었음 그 때 set~~~()
모양의 값을 정하거나 값을 바꾸는 함수를 넣을 수 있는데 여기에 immer
의 produce
의 updater
를 사용하면 좀 더 쉽게 불변성 유지가능