[JS/React] 객체 spread 문법으로 참조형 state 변경하기

소연·2023년 11월 27일

일러두기

  • 본 글은 ‘모던 자바스크립트 Deep Dive’ 35.3장, ‘스프레드 문법: 객체 리터럴 내부에서 사용하는 경우’를 참고하여 작성되었습니다.
  • 글에 틀린 점이 있다면 댓글로 피드백 부탁드립니다 :)

참조형 state의 값을 바꿀 땐 새로운 객체를 만들어야 한다


참조형 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를 추가하면 문제가 생기는 것 아닌가?’ 싶었다. 객체가 병합될 때 이런 규칙이 있었다는 것을 알고 나서 보면 쉽게 이해되는 코드이다.

0개의 댓글