useState로 상태를 관리하던 중 array/object 자료를 수정, 추가, 삭제할때 중첩 객체와 같이 자료가 복잡해지면 스프레드 연산자를 사용하여 객체를 복사하여 수정, 추가, 삭제와 같은 조작을 했을때 코드가 직관적이지 않고 알아보기 힘들 수 있다. 이를 스프레드 연산자를 사용하지 않고 간편하게 조작할 수 있는 라이브러리로 immer, useImmer 가 있다.
import React, { useReducer, useState } from 'react';
import { useImmer } from 'use-immer';
export default function AppMentorsImmer() {
const [person, updatePerson] = useImmer(initialPerson);
// const [person, dispatch] = useReducer(personReducer, initialPerson)
const handleUpdate = ()=>{
const prev = prompt(`누구의 이름을 바꾸고 싶은가요?`);
const current = prompt(`이름을 무엇으로 바꿀것인가요?`);
updatePerson(person => {
const mentor = person.mentors.find(m => m.name === prev);
mentor.name = current;
})
}
const handleAdd = ()=>{
const name = prompt(`추가할 멘토의 이름`);
const title = prompt(`추가할 멘토의 타이틀`);
updatePerson((person) => {
person.mentors.push({name, title});
})
}
const handleDelete = ()=>{
const deleteName = prompt(`삭제할 멘토 이름`);
updatePerson(person => {
const index = person.mentors.findIndex(m => m.name === deleteName);
if(index < 0) return; //이 코드 없으면 li에 없는 사람 입력해서 삭제하면 맨 마지막 요소 삭제됨
person.mentors.splice(index, 1);
})
}
return (
<div>
<h1> {person.name}은 {person.title} </h1>
<p> {person.name}의 멘토는 :</p>
<ul>
{person.mentors.map((mentor, index)=>{
return <li key={index}>
{mentor.name} ({mentor.title})
</li>
})}
</ul>
<button onClick={handleUpdate}>멘토의 이름 바꾸기</button>
<button onClick={handleAdd}>멘토 추가</button>
<button onClick={handleDelete}>멘토 삭제</button>
</div>
);
}
const initialPerson = {
name : '화랑',
title : '프론트 개발자',
mentors : [
{
name : '멜리오다스',
title : '단장',
},
{
name : '킹',
title : '요정',
},
],
}
useState로 관리하던 person, setPerson state를 useImmer를 사용하여
person, updatePerson 으로 수정하고 useImmer의 매개변수에 초기 person 값을 넣어줬다.
이후 setPerson으로 state값을 업데이트하던 부분에 대신 updatePerson()을 넣고 더 직관적으로 수정하고싶은 부분을 수정하면 된다.
코드가 겉보기엔 원본 자체를 수정하는것 처럼 보이지만 immer 내부적으로 새로운 person이란 객체를 만들어서 update하는 부분만 변경해준다.
updatePerson( person => {
const mentor = person.mentors.find(m => m.name === prev);
mentor.name = current;
}
이렇게 스프레드 연산자를 사용하지 않고도 객체를 수정할 수 있다.