immer 맛보기

why immer?

immer는 불변 객체의 내용을 수정하는 경우에 사용한다. 불변 객체의 내용을 수정하여 새로운 불변 객체를 만들어 낸다.

리엑트에서 렌더링을 위해 원래 객체 또는 배열의 내용을 바꾸지 않고 새로운 객체 또는 배열을 생성해야 한다.

객체의 내용이 또 다른 객체나 배열로 이루어져 있으면 해당 내용만 복사한 새로운 객체를 만들기 위해 불편함이 따른다.

const obj = {
    a: {
        id: 1
    },
    b: {
        id: 2
    }   
}

const newObj = {
    ...obj
}
console.log(obj);       //{ a: { id: 1 }, b: { id: 2 } }
console.log(newObj);    //{ a: { id: 1 }, b: { id: 2 } }
obj.a.id = 10;
console.log(obj);       //{ a: { id: 10 }, b: { id: 2 } }
console.log(newObj);    //{ a: { id: 10 }, b: { id: 2 } }

불변성을 유지하면서 객체를 생성하기 위해 전개 연산자를 사용했지만 객체 내부 객체는 깊은 복사가 이루어지지 않아 불변성이 깨지는 것을 확인할 수 있다. 이렇게 객체 구조가 복잡하면 전개 연산자만으로 불변성을 유지하기 귀찮아진다.

이러한 귀찮음을 해결하기 위해 immer 라이브러리를 활용한다.

produce

immer는 불변성을 유지하면서 객체를 수정하기 위한 함수 produce를 제공한다.

produce(currentState, producer)

produce함수의 첫번째 파라미터는 현재 상태고 두번째 파라미터는 해상 상태를 업데이트할 producer함수다.

currentState는 바꾸지 않은 채 새로운 상태를 리턴한다.

const studentList =  [
    {
        id: 1,
        name: "James"
    },
    {
        id: 2,
        name: "Lina"
    },
]

const nextStudentList = produce(studentList, draft => {
    const student = { id: 3, name: "Smith"}
    draft.push(student)
})

두번째 매개변수인 producer함수의 파라미터 draftcurrentState를 가리키는 proxy역할을 한다.

curried producer

produce함수의 파라미터로 함수를 준다면 업데이트 함수를 반환한다.


const updateValue = produce(draft => {
    draft.value = 10
})

const original = {
    value: 1
}

const nextState = updateValue(original)

console.log(nextState) // {value: 10}