본문 바로가기

리액트

[react] 리액트에서 상태에 대한 정리(2) - 객체

반응형

- 리액트 공식문서를 읽고 이해한 부분을 정리한 포스트 입니다. -

 

리액트에서 객체의 상태는 읽기 전용으로 취급해야 한다.

리액트에서는 상태(state) 는 불변해야 한다. 이는 리액트의 최적화 전략과 관련된다. 리액트는 이전 프로퍼티나 상태가 다음 프로퍼티나 상태와 동일한 경우에는 작업을 건너뛰는 방식을 채택한다. 이는 리액트의 가상돔 방식과도 이어지는 것으로 리액트는 변경 이전의 값과 변경 이후의 값이 일치하지 않으면 업데이트를 실행하고, 그게 아니라면 업데이트를 건너 뛴다.

 

이는 객체를 취급할 때도 마찬가지다. 예를 들어, 다음 코드가 있다고 가정 해보자

import { useState } from 'react';

export default function MovingDot() {
  const [position, setPosition] = useState({
    x: 0,
    y: 0
  });
  return (
    <div
      onPointerMove={e => {
        position.x = e.clientX;
        position.y = e.clientY;
      }}  }}>
    </div>
  );
}

 

위 코드에서 setState 로 생성된 position 이라는 상태(state)는 불변해야 한다.  리액트는 상태를 직접적으로 변경하지 않고, 상태의 복사본을 변경하여 리렌더링 시 대체하는 방식으로 업데이트 되는데, 상태를 직접적으로 변경 해버리면 리액트가 고수하는 불변성을 깨뜨리기 때문이다. 또한 리액트는 스냅샷 형식으로 상태를 관리하는데, 상태의 직접적 변경(이를 변이라 한다.)은 스냅샷 당시의 상태(이전 상태)를 변경하는 것으로 이는 리렌더링을 발생시키지 않는다. 즉, 상태에 변경이 발생해도 리액트는 이를 렌더링에 반영하지 않는다. 

 

따라서 해당 position 이라는 변수에 position.x = e.clientX 와 같이 직접 접근 하여 객체의 값을 변경시키는 것은 금해야 한다.

 

위 코드를 올바르게 수정하면 다음 코드가 된다.  

import { useState } from 'react';

export default function MovingDot() {
  const [position, setPosition] = useState({
    x: 0,
    y: 0
  });
  return (
    <div
      onPointerMove={e => {
        setPosition ({
        position.x = e.clientX;
        position.y = e.clientY;
        })
      }}>
    </div>
  );
}

 

이렇게 되면 리액트는 position 을 직접 변경하는 것이 아니라 내부적으로 상태의 복사본을 생성하여 이를 변경 후 해당 컴포넌트를 리렌더링한다. 이 때 position 는 이전 상태를 버리고 새로운 상태로 완전히 대체 된다. 

반응형