본문 바로가기

프론트엔드

[프론트엔드] 리액트에서 상태관리는 어떻게 이루어질까? (Feat: useState)

 

결론부터 말하자면 리액트의 상태관리는 비동기적으로 이루어진다.

 

만약 리액트의 특성을 모른채로 개발을 진행하다가 상태를 업데이트한 직후에 바로 해당 값을 사용할 경우, 기대한 최신 값이 아니라 이전 상태의 값이 사용될 수 있는 여지가 있다. 예를 들어, 다음과 상황이 있을 수 있다. 

가위바위보 사이트

const [userSelect, setUserSelect] = useState(null);
const [computerSelect, setComputerSelect] = useState(null);

  const play = (item) => {
    setUserSelect(userSelect);
    setComputerSelect(computerSelect);

    judge(userSelect, computerSelect);
  };

 

이 예시는 사용자가 화면 가운데 있는 '가위', '바위', '보' 세가지 버튼 중 하나를 클릭했을때, 컴퓨터도 세가지 선택지 중 하나를 랜덤하게 선택하도록 하고, 이 선택에 기반하여 변경된 상태를 judge 함수의 인자값으로 넣어줘 컴퓨터와 사용자 중 누가 이겼는지를 판별해주는 로직이다. 언뜻 보기엔 동기적으로 잘 작동할 것 같고, 아무 문제가 없어보인다.

하지만, 이를 실행할 경우, 이와 같은 에러메시지를 만나게 된다. 

TypeError: Cannot read properties of null (reading 'name')

 

 

그 이유는 judge의 인자값이 되는 userSelect와 computerSelect라는 두 상태의 초기값이 null로 초기화 되어 있어, judge 내부에서 이를 기반으로 연산을 진행할려고 하다보니 에러가 발생하게 되는 것이다.

 

그래서 상태 업데이트 직후에 그 값을 사용해야 하는 경우, 업데이트된 값을 안전하게 사용하기 위해 상태 업데이트와 함께 

필요한 값을 변수에 저장한 후 사용하거나, 상태 업데이트 후에 특정 작업을 수행하려면 useEffect 훅을 활용해야 한다.

 

즉, 앞선 예시의 코드는 동기적으로 작동된 것처럼 보이지만, 사실은 React의 상태 업데이트가 비동기적으로 처리된다는 것을 보여주는 하나의 사례이다.

 

비동기 상태 업데이트의 이유

그렇다면 의문이 드는 것은 왜 리액트는 상태 업데이트를 비동기적으로 하는 것일까? 

찾아보니 역시나 성능 이슈 때문인데, 성능 최적화를 위해 리액트는 여러 상태 업데이트를 일괄 처리할 수 있도록 하기 위해 상태 업데이트가 비동적으로 처리되도록 스케줄링한다고 한다.

 

생각해보면 굉장히 그럴듯한것이 만약 하나의 상태 업데이트가 발생할 때마다 React가 즉시 재랜더링된다면, 랜더링이 너무 많이 발생할 것 같다. 반면, 여러 업데이트를 묶어서 한 번에 처리하도록 한다면, 이전에 비해 랜더링 횟수가 줄고, 성능을 최적화할 수 있을 것 같다. 

그리고 실제로 이렇게 한다고 한다. 

 

요약

정리하자면, 상태가 변경되면 React는 해당 컴포넌트를 다시 렌더링해야 한다고 판단하여 업데이트 사이클을 시작한다.

이 렌더링은 비동기적으로 처리되며, 여러 상태 변경이 하나의 사이클에서 일괄 처리되기도 한다.

이를 통해 React는 불필요한 렌더링을 방지하고, 더 나은 성능을 유지한다.