const state = {
posts: [
{
id: 1,
title: '제목입니다.',
body: '내용입니다.',
comments: [
{
id: 1,
text: '와 정말 잘 읽었습니다.'
}
]
},
{
id: 2,
title: '제목입니다.',
body: '내용입니다.',
comments: [
{
id: 2,
text: '또 다른 댓글 어쩌고 저쩌고'
}
]
}
],
selectedId: 1
};
posts
배열 안의 id
가 1
인 post
객체를 찾아서, comments
에 새로운 댓글 객체를 추가해줘야한다고 가정하면, 다음과 같이 업데이트 해줘야 할 것이다.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
는 이처럼 상태를 업데이트할 때, 불변성을 신경쓰지 않으면서 업데이트 해주면 알아서 불변성 관리를 대신 해준다.1) Immer 설치
$ yarn add immer
2) 코드 상단에서 immer 불러오기
import produce from 'immer';
3) 첫번째 파라미터에는 수정하고 싶은 상태, 두번째 파라미터에는 어떻게 업데이트하고 싶을지 정의하는 함수를 넣어주기
const state = {
number: 1,
dontChangeMe: 2
};
const nextState = produce(state, draft => {
draft.number += 1;
});
console.log(nextState);
// { number: 2, dontChangeMe: 2 }
useState
로 함수형 업데이트를 한다. Immer
를 활용해 간편하게 useState
를 사용할 수 있다.produce
함수에 첫번째 파라미터를 생략하고 바로 업데이트 함수를 넣어주게 된다면, 반환 값은 새로운 상태가 아닌 상태를 업데이트 해주는 함수가 된다. 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 }
produce
가 반환하는 것이 업데이트 함수가 되기 때문에 useState
의 업데이트 함수를 사용할 때 다음과 같이 구현할 수 있게 된다.const [todo, setTodo] = useState({
text: 'Hello',
done: false
});
const onClick = useCallback(() => {
setTodo(
produce(draft => {
draft.done = !draft.done;
})
);
}, []);
Immer
를 사용하지 않은 코드가 조금 더 빠르다.Immer
를 사용하는 것이 좋다.