iOS 개발자가 React 배우기: state의 불변성

SteadySlower·2024년 10월 31일
0

React JS

목록 보기
5/13

state의 불변성은 무엇인가?

SwiftUI에서는 @State로 선언된 struct의 property를 변경하면 UI가 업데이트 된다. 왜냐하면 struct를 value type이기 때문에 property가 바뀌면 다른 값으로 인식하기 때문이다.

React에서 useState()로 선언된 object의 값을 바꾸면 동일하게 작동할까? 실제로 해보면 UI가 업데이트 되지 않은 것을 볼 수 있다.

이는 javascript의 object는 reference type인 swift의 class와 동일하게 참조값이 바뀌지 않으면 동일한 객체로 취급되기 때문이다.

따라서 useState로 선언된 State는 불변성을 가져야 한다. 그렇다면 UI를 업데이트 하기 위해서는 어떻게 해야할까? UI를 업데이트하기 위해서는 참조 값 자체를 바꾸어야 한다.

아래 예시 코드처럼 기존의 object를 복사해서 완전히 새로운 object를 만들면 된다.

    const [student, setStudent] = useState({
        name: "홍길동",
        class: 1,
        subjects: [
            { name: "국어", teacher: "김국어" },
            { name: "영어", teacher: "이영어" },
        ],
    });

    const changeName = (name) => {
        setStudent((prev) => ({
            ...prev,
            name,
        }));
    };

    const addSubject = (subject, teacher) => {
        setStudent((prev) => ({
            ...prev,
            subjects: [...prev.subjects, { subject, teacher }],
        }));
    };

    const removeSubject = (subject) => {
        setStudent((prev) => ({
            ...prev,
            subjects: prev.subjects.filter((s) => s.name !== subject)
        }))
    }

Immer

공식 사이트

위처럼 간단한 구조의 object를 사용할 때는 큰 문제가 없지만 object가 복잡해지면 object를 수정하는 코드도 그만큼 길어진다.

이런 경우에 좀 더 State의 불변성을 유지하는데 도움을 주는 라이브러리가 Immer이다.

Immer의 경우 아래처럼 useState 대신에 useImmer를 사용하여 State를 관리할 수 있도록 해주는데 이를 활용하면 아래와 같이 object를 직접 수정하는 경우에도 라이브러리가 불변성을 유지할 수 있도록 해주기 때문에 코드를 짧게 유지할 수 있다.

    const [student, updateStudent] = useImmer({
        name: "홍길동",
        class: 1,
        subjects: [
            { name: "국어", teacher: "김국어" },
            { name: "영어", teacher: "이영어" },
        ],
    });

    const changeName = (name) => {
        updateStudent((student) => (student.name = name));
    };

    const addSubject = (subject, teacher) => {
        updateStudent((student) => (student.subject.push({name: subject, teacher})))
    };

    const removeSubject = (subject) => {
        updateStudent((student) => {
            const index = student.subjects.findIndex((s) => s.name === subject)
            student.subjects.splice(index, 1)
        })
    };
profile
백과사전 보다 항해일지(혹은 표류일지)를 지향합니다.

0개의 댓글

Powered by GraphCDN, the GraphQL CDN