React - immer, useImmer

thisishwarang·2023년 1월 30일
0

immer, useImmer

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;
}

이렇게 스프레드 연산자를 사용하지 않고도 객체를 수정할 수 있다.

0개의 댓글