
참조형 State 사용의 잘못된 예
const [state, setState] = useState({ count: 0 });
const handleAddClick = () => {
state.count += 1; // 참조형 변수의 프로퍼티를 수정
setState(state); // 참조형이기 때문에 변수의 값(레퍼런스)는 변하지 않음
}
react에서 참조형 state를 만들었으면 값을 바꿀 때도 주의해야 한다. 위 코드에서처럼, state 객체에 직접 점 표기법으로 접근하여 값을 수정해서는 안된다. 얼핏 보면 setState(state)로 바뀐 값을 업데이트 하는 것 처럼 보이나, state라는 식별자에는 객체에 접근할 수 있는 주솟값 (레퍼런스)가 할당되어있기 때문에 점 표기법을 사용해 값을 변경하였어도 리액트는 그 변화를 알 수 없다.
리액트가 그 변화를 감지하지 못한다는 뜻은 곧 재렌더링이 일어나지 않는다는 뜻과 같다.
참조형 State 사용의 올바른 예
const [state, setState] = useState({ count: 0 });
const handleAddClick = () => {
setState({ ...state, count: state.count + 1 }); // 새로운 객체 생성
}
그렇다면 리액트가 변화를 알도록 state객체의 값을 바꿔주는 방법은 뭐가 있을까? 그냥 새 객체를 만들어 주면 된다. 추가할 값이 담긴 새로운 객체를 생성해 state에 그 새로운 객체를 가리키는 주솟값을 할당해주는 것이다.
그리고 여기에서 등장한 JS 문법이 객체 spread를 통한 프로퍼티 변경인데, 조금 더 살펴보고자 모던 자바스크립트 딥 다이브 책을 폈다.
다음은 두 객체 { x: 1, y: 2 } { y: 100}을 병합하는 코드이다.
프로퍼티가 중복되는 경우 뒤에 위치한 프로퍼티가 우선권을 갖는다
// 특정 프로퍼티 변경
const changed = {...{x:1, y:2}, y:100}
// === const changed = {...{x:1, y:2}, ...{y:100}}
console.log(changed) // {x:1, y:100}
“프로퍼티가 중복되는 경우, 뒤에 위치한 프로퍼티가 우선권을 갖”기 때문에 첫번째 객체의 y:2 보다 두번째 객체의 y:100이 우선권을 갖는다. 따라서 changed 식별자에는 y:100 이 할당된 새로운 객체의 레퍼런스가 할당된다. 그래서 아래와 같은 코드로 참조형 state의 값을 수정할 수 있었던 것이었다!
const [state, setState] = useState({ count: 0 });
const handleAddClick = () => {
setState({ ...state, count: state.count + 1 }); // 새로운 객체 생성
}
처음 이 코드를 보았을 땐 ‘이미 기존 state에 count라는 속성이 있는데, 새로운 count를 추가하면 문제가 생기는 것 아닌가?’ 싶었다. 객체가 병합될 때 이런 규칙이 있었다는 것을 알고 나서 보면 쉽게 이해되는 코드이다.