본문 바로가기
FE/React

[React Official Document] #4 State as a snapshot

by aeyong-dev 2023. 9. 28.

우리는 useState를 사용하여 컴포넌트의 상태를 관리한다. 
컴포넌트의 상태가 바뀌면 그 컴포넌트는 리렌더링된다. 
문서는 이 과정에 대해 설명하고 있다. 
상태에 따른 리렌더링의 원리와 과정, 그리고 앞으로 배울 것에 대해 자연스럽게 이해할 수 있다.
 
https://react.dev/learn/state-as-a-snapshot

State as a Snapshot – React

The library for web and native user interfaces

react.dev


setState()는 렌더링을 일으킨다

setState()는 상태를 나타내는 변수를 바꾼다고 생각할 수 있다. 
하지만 틀렸다.
setState()는 리렌더링을 일으키는 것이다. 
페이지 내의 이벤트(버튼 클릭 등)를 제어하기 위해서는 상태를 업데이트 해야한다. 
버튼의 클릭 이벤트를 예로 들자면, 

  1. onClick 이벤트가 실행된다.
  2. setState()가 상태를 업데이트한다.
  3. 리액트가 업데이트된 상태에 따라 페이지를 리렌더링한다.

리렌더링의 스냅샷

리렌더링은 함수(형 컴포넌트)를 호출하는 것이다.
컴포넌트가 렌더링 될 때 props, 이벤트핸들러, 지역변수들은 렌더링 시점의 상태를 기준으로 계산된다.
리액트가 UI의 스냅샷(로직을 포함한다)과 일치하도록 화면을 업데이트하고 이벤트 핸들러를 연결함으로써,
버튼을 누르는 것이 클릭 핸들러를 일으키는 것이다.
말이 복잡하다. 간단하게 정리하자면 다음과 같다. 

<리렌더링의 과정>

1. 함수 호출: 호출 시점 기준으로 props, eventHandler, 지역변수 계산함
2. 화면 업데이트: UI의 스냅샷과 일치하도록
3. 이벤트 핸들러 연결: UI 스냅샷에 포함돼있음
4. DOM 트리 업데이트

컴포넌트의 메모리에서, state는 함수가 return하면 사라지는 일반적인 변수와 다르다.
state는 함수 바깥의 리액트에서 살아있다.
아래 그림을 보면 이해하기 쉬울것이다.

출처: 리액트 공식 문서

다음 예시를 통해 확실하게 알아보자.

import { useState } from 'react';

export default function Counter() {
  const [number, setNumber] = useState(0);

  return (
    <>
      <h1>{number}</h1>
      <button onClick={() => {
        setNumber(number + 1);
        setNumber(number + 1);
        setNumber(number + 1);
      }}>+3</button>
    </>
  )
}

버튼을 누르면 number의 값은 어떻게 변할까? 
당연히 3으로 변할 것이다.. 라고 생각했지만, number는 1이 된다. 
onclick과 같은 이벤트가 발생하면, 
발생 시점 기준으로 상태가 계산된다.
그러니까, setNumber(0+1); 을 세번 한 것이다. 
상태는 오직 다음의 렌더링 시점에만 변한다. 
한번의 렌더링에서 상태가 세 번 변할 수는 없는 것이다.
 

시간과 상태

그럼 다음의 상황에서는 값이 어떨까?

import { useState } from 'react';

export default function Counter() {
  const [number, setNumber] = useState(0);

  return (
    <>
      <h1>{number}</h1>
      <button onClick={() => {
        setNumber(number + 5);
        setTimeout(() => {
          alert(number);
        }, 3000);
      }}>+5</button>
    </>
  )
}

당연히 0이 나온다. 
숫자는 누름과 동시에 5가 되지만 알림은 0이 출력된다.
아까 말했듯이 이벤트는 발생 시점의 상태를 가진다. 
발생 시점, 그러니까 초기 상태는 0이므로 0이 나오는 것이다. 
이벤트 핸들러에서 리액트는 state 값을 고정된 값을 가진다. 
심지어 이벤트 핸들러가 비동기 함수로 작성되어도 state값은 절대 바뀌지 않는다!
혹시 어렵게 느껴진다면, state 변수 대신 렌더링 이전의 값을 넣어서 생각해보자. 
 
이 덕분에 우리는 실행중에 상태가 바뀌지 않을지 걱정하지 않아도 된다. 
하지만 만약 리렌더링 이전의 최근 값을 읽고싶다면 어떻게 해야할까?
상태 업데이트 함수를 사용하면 된다. 
그런데 그건.. 
다음 포스팅에서 알아보자!