1. 개요
React를 처음 접하며 state를 업데이트할 때 항상 스프레드 연산자를 사용해야 한다는 점이 이해가 잘 가지 않았습니다.
"어차피 값을 변경하는 것은 똑같은데, 왜 state를 직접 변경하지 않고 굳이 스프레드 연산자를 사용해서 새로운 객체를 만들어야 할까?"
이러한 의문을 C++ 관점에서 파헤쳐봤습니다.
2. 불변성(Immutability)이란?
불변성이란 한번 생성된 데이터가 수정되지 않아야 한다는 원칙이다.
데이터를 변경해야 할 때는 원본을 직접 수정하지 않고, 해당 데이터를 복사한 새로운 데이터를 생성해야 한다.
C++에서는 객체의 불변성을 유지하기 위해 주로 const 키워드를 사용한다.
const int number = 42; // 값을 변경할 수 없음
const User user{"Kim"}; // 객체의 상태를 변경할 수 없음
JavaScript에도 const가 있지만, 객체의 내부 속성 변경은 허용된다.
const user = { name: "Kim" };
user.name = "Lee"; // 허용됨
user = { name: "Park" }; // 에러: 재할당 불가
즉, const만으로는 불변성을 유지할 수 없다는 것이다.
이러한 특성 때문에 JavaScript에서는 불변성을 유지하기 위해 새로운 객체를 생성하는 방식을 사용한다.
3. React에서 불변성이 중요한 이유
React에서 state의 불변성을 유지해야 하는 주요 이유는 다음과 같다.
1) 렌더링 최적화
React는 state가 변경되었는지 판단하기 위해 이전 state와 새로운 state를 비교한다.
이때 성능을 위해 얕은 비교(메모리 주소 비교)를 수행한다.
ex)
const [count, setCount] = useState(0);
// 메모리 주소가 다른 새로운 값이 할당되므로 변화를 감지한다
setCount(count + 1);
const [user, setUser] = useState({ name: "Kim" });
user.name = "Lee"; // 같은 메모리 주소의 객체를 수정
setUser(user); // React는 변화를 감지하지 못한다
2) 상태 관리
상태 변화가 명확하고 추적 가능해져 디버깅이 용이하다.
모든 상태 변경이 setState를 통해 이루어지므로 데이터 흐름을 추적하기 쉽다.
3) 부작용 방지
여러 컴포넌트가 같은 데이터를 참조할 때 의도치 않은 데이터 변경을 방지할 수 있다.
특히 비동기 작업에서 데이터 일관성을 유지하기 쉬워진다.
4. React의 State 업데이트 방식
React는 state의 변화를 감지할 때 참조값의 변경을 확인한다.
JavaScript에서 객체를 복사할 때는 최상위 객체만 새로운 참조가 생성되고 내부 객체들은 여전히 원본의 참조를 유지한다.
이는 C++에서 얕은 복사(shallow copy)와 유사한 개념이다.
C++ 예시)
struct Address {
string city;
string street;
};
struct User {
string name;
Address* address; // 포인터 사용
};
User* user = new User{
"Kim",
new Address{"Seoul", "강남대로"}
};
// address 포인터가 가리키는 값을 직접 수정
user->address->street = "역삼로"; // 원본 데이터 변경
// 새로운 Address 객체 생성
user->address = new Address{ // 새로운 메모리 할당
user->address->city,
"역삼로"
};
React 예시)
const [user, setUser] = useState({
name: "Kim",
address: {
city: "Seoul",
street: "강남대로"
}
});
// 잘못된 방식 (C++의 포인터를 통한 직접 수정과 유사)
user.address.street = "역삼로";
setUser(user); // 참조가 같아서 변화 감지 불가
// 올바른 방식 (새로운 객체 생성)
setUser({
...user,
address: {
...user.address,
street: "역삼로"
}
});
5. 결론
React에서 불변성을 유지하는 것은 단순한 규칙이 아니라 애플리케이션의 안정성과 성능을 위한 중요한 원칙이다.
불변성을 통해 React는 효율적으로 상태 변화를 감지하고, 개발자는 예측 가능한 방식으로 상태를 관리할 수 있다.
그러므로 실제 개발에서는 다음 사항들을 항상 유념해야 한다.
- state를 직접 수정하지 않고 항상 setState를 통해 업데이트한다.
- 객체를 업데이트할 때는 스프레드 연산자를 사용하여 새로운 참조를 생성한다.
- 중첩된 객체의 경우, 수정이 필요한 모든 레벨에서 새로운 참조를 생성한다.
6. 마무리
글을 적다보니 요즘시대에 C++을 먼저 배우고 리액트를 배우는 사람이 얼마나 있을까 싶긴 하네요.
앞으로는 C++얘기는 최대한 빼야될것같아요
'학습 > React' 카테고리의 다른 글
리액트 기초 - 강의 정리 2 (0) | 2025.02.25 |
---|---|
리액트 기초 - 강의 정리 1 : JSX, 컴포넌트, 렌더링 (0) | 2025.02.21 |
useCallback (1) | 2025.01.30 |
React 기초 (0) | 2024.12.21 |
개요 (1) | 2024.11.16 |