[React] State as a Snapshot

HyeonE·2024년 5월 4일
0

React

목록 보기
12/12
post-thumbnail

state 변수는 읽고 쓸 수 있는 일반 JavaScript 변수처럼 보일 수 있습니다. 하지만 state는 스냅샷처럼 동작합니다. state 변수를 설정해도 이미 가지고 있는 state 변수는 변경되지 않고, 대신 리렌더링이 실행됩니다.

⚙️ state를 설정하면 렌더링이 실행됩니다

Click 과 같은 유저 이벤트에 반응하여 사용자 인터페이스가 직접 변경된다고 생각할 수 있습니다. 하지만, React 에서는 이런 과정과는 조금 다르게 작동합니다. React 에서는 state를 설정하면 리렌더링을 요청하게 됩니다. 즉, 유저의 이벤트에 반응하려면 state를 업데이트해야 합니다.

  • 유저가 submit를 누르면 setIsSent(true)가 되면서 state가 업데이트 됩니다.
    -> 이때, component의 리렌더링이 발생하게 됩니다.
import { useState } from 'react';

export default function Form() {
  const [isSent, setIsSent] = useState(false);
  const [message, setMessage] = useState('Hi!');
  
  if (isSent) {
    return <h1>Your message is on its way!</h1>
  }
  
  return (
    <form onSubmit={(e) => {
      e.preventDefault();
      setIsSent(true);
      sendMessage(message);
    }}>
      <textarea
        placeholder="Message"
        value={message}
        onChange={e => setMessage(e.target.value)}
      />
      <button type="submit">Send</button>
    </form>
  );
}

function sendMessage(message) {
  // ...
}

💻 렌더링은 그 시점의 스냅샷을 찍습니다

사진이나 동영상 프레임과 달리 반환하는 UI Snapshot은 대화형입니다. 여기에는 input, button 등에 대한 응답으로 어떤 일이 일어날지 지정하는 이벤트 핸들러와 같은 로직이 포함됩니다. 그러면 React는 이 Snapshot과 일치하도록 화면을 업데이트하고 이벤트 핸들러를 연결합니다.

  1. React가 함수를 다시 호출합니다.
  2. 함수가 새로운 JSX 스냅샷을 반환합니다.
  3. 그러면 React가 반환한 스냅샷과 일치하도록 화면을 업데이트합니다.

컴포넌트의 메모리로서 state는 함수가 반환된 후 사라지는 일반 변수와 다릅니다. state는 실제로 함수 외부에 마치 선반에 있는 것처럼 React 자체에 “존재”합니다. React가 컴포넌트를 호출하면 특정 렌더링에 대한 state의 Snapshot을 제공합니다. 컴포넌트는 해당 렌더링의 state 값을 사용해 계산된 새로운 props 와 이벤트 핸들러가 포함된 UI의 스냅샷을 return 해줍니다.

  • 이 코드에서는 ‘+3’ 버튼을 클릭하면 setNumber(number + 1)를 세 번 호출하므로 세 번 증가할 것으로 예상할 수 있습니다.
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>
    </>
  )
}

setNumber(number + 1)를 세 번 호출했지만, 이 렌더링에서 이벤트 핸들러의 number는 항상 0이므로 state를 1로 세 번 설정했습니다. 이것이 이벤트 핸들러가 완료된 후 React가 컴포넌트 안의 number 를 3이 아닌 1로 다시 렌더링하는 이유입니다.

React에서 상태를 업데이트할 때 setState 또는 useState hooksetter 함수를 호출하면 현재 상태를 업데이트하는 것이 아니라, 다음 렌더링 사이클에서 적용될 새로운 상태를 예약하는 것입니다.

따라서, 여러 번 setNumber(number + 1)을 호출하더라도 현재 렌더링 사이클에서는 number 값이 업데이트되지 않습니다. 각 호출에서 number는 여전히 0으로 유지됩니다. 그래서 이벤트 핸들러가 완료된 후 React는 컴포넌트를 다시 렌더링하고, 해당 시점에 number의 값은 이미 1로 설정되어 있습니다.

만약, 위의 코드에서 numberd의 값을 3으로 바꾸고 싶다면 아래와 같은 로직을 따를 수 있을 것 같습니다.

import { useState } from 'react';

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

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

prev => prev + 1함수형 업데이트를 사용하는 방법입니다. 이 방법은 이전 상태를 활용하여 새로운 상태를 설정하는 데 사용됩니다.

이전에 설명한 것처럼 setNumber(prev => prev + 1)을 사용하면 현재 상태가 아닌 이전 상태를 기반으로 값을 업데이트합니다. 이것은 비동기적으로 상태를 업데이트하고, 여러 번의 setNumber 호출이 있을 때 이전 상태를 올바르게 기반으로 새로운 값을 설정할 수 있습니다.

따라서 위의 코드에서 setNumber(prev => prev + 1)을 사용하여 이전 상태를 기반으로 1씩 증가시키는 것도 가능합니다. 이 방법을 사용하면 이벤트 핸들러가 실행될 때마다 현재 상태가 아닌 이전 상태를 기반으로 값을 업데이트하므로 의도대로 동작할 것입니다.

📝 마무리(요약)

React에서 useState를 사용하여 상태를 설정하면, 해당 렌더링에 대한 상태의 스냅샷이 생성됩니다. 이를 통해 React는 상태의 변경을 추적하고, 다음 렌더링 사이클에서 변경된 상태를 반영합니다. 컴포넌트 외부에 마치 선반에 보관하는 것처럼 상태를 저장하고, useState를 호출하면 해당 렌더링에 대한 상태 스냅샷을 제공합니다.

변수와 이벤트 핸들러는 다시 렌더링되어도 "살아있지" 않습니다. 즉, 변수와 이벤트 핸들러는 각각의 렌더링마다 "재생성"됩니다. 각 렌더링은 자체적인 이벤트 핸들러를 가지며, 모든 렌더링과 그 안에 있는 함수는 항상 해당 렌더링에 제공된 상태의 스냅샷을 보게 됩니다. 이 때, 과거에 생성된 이벤트 핸들러는 해당 렌더링 시점의 상태 값을 갖게 됩니다.

React의 이러한 원리를 이해하면 React 컴포넌트의 동작을 더 잘 이해하고, 상태와 이벤트 처리를 효과적으로 다룰 수 있다고 생각합니다. 아직 어려운 부분들이 있지만 실전에서 코드를 많이 다뤄보며 더욱 공부하는 노력을 해볼려고 합니다.

profile
프론트엔드 개발자가 되고싶은 대학생

0개의 댓글

관련 채용 정보