HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
🐣
프론트엔드 데브코스 4기 교육생
/
🐶
이재호2팀
/
🌰
리액트 스터디
/
🌳
10월12일 목요일 1차스터디(Adding Interactivity - 상호작용 추가하기)
/
스냅샷으로서의 state

스냅샷으로서의 state

  • state 변수는 읽고 쓸 수 있는 일반 JavaScript 변수로 보일 수 있다.
    • 그러나 state는 스냅샷처럼 동작한다.
    • state 변수를 설정해도 이미 가지고 있는 state 변수는 변경되지 않고, 대신 리렌더링이 실행된다.
  1. state를 설정하면 렌더링이 트리거된다.
      • 클릭과 같은 사용자 이벤트에 반응하여 사용자 인터페이스가 직접 변경된다고 생각할 수 있다.
      • 그러나 React에서는 이와는 조금 다르게 동작한다.
      인터페이스가 이벤트에 반응하려면 state를 업데이트 해야 한다.
      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) { // ... }
      • send를 누르면 setIsSent(true)가 React에 UI를 다시 렌더링하도록 지시한다.
      • 버튼을 클릭하면 아래와 같은 일들이 발생한다.
          1. onSubmit 이벤트 핸들러가 실행된다.
          1. setIsSent(true)가 isSent를 true로 설정하고 새 렌더링을 큐에 대기시킨다.
          1. React는 새로운 isSent값에 따라 컴포넌트를 다시 렌더링한다.
  1. 렌더링은 그 시점의 스냅샷을 찍는다.
      • 렌더링이란 React가 컴포넌트, 즉 함수를 호출한다는 뜻이다. 해당 함수에서 반환하는 JSX는 시간에 따른 UI의 스냅샷과 같다.
        • props, 이벤트 핸들러, 로컬 변수는 렌더링 당시의 state를 사용해 계산된다.
      • 사진이나 동영상과 달리 반환하는 UI '스냅샷' 은 인터렉티브 하다.
        • 여기에는 input에 대한 응답으로 어떤 일이 일어날지 지정하는 이벤트 핸들러와 같은 로직이 포함된다.
        • React는 이 스냅샷과 일치하도록 화면을 업데이트하고, 이벤트 핸들러를 연결한다.
        • 결과적으로 버튼을 누르면 JSX에서 클릭 핸들러가 발동된다.
      • React가 컴포넌트를 다시 렌더링할 때
          1. React가 함수를 다시 실행한다.
          1. 함수가 새로운 JSX 스냅샷을 반환한다.
          1. React가 반환된 스냅샷과 일치하도록 화면을 업데이트 한다.
            1. notion image
      • 컴포넌트의 메모리로서 state는 함수가 반환된 후 사라지는 일반 변수들과는 다르다.
        • state는 실제로 외부 함수에 마치 선반(shelf) 이 있는것 처럼, React 자체에 존재한다.
        • React가 컴포넌트를 호출하면 특정 렌더링에 대한 state의 스냅샷을 제공한다.
        • 컴포넌트는 해당 렌더링의 state값을 사용해 계산된 새로운 props 세트와 이벤트 핸들러가 포함된 UI의 스냅샷을 JSX에 반환한다.
          • notion image
      • 이를 설명하는 간단한 예제가 아래에 있다. 실행을 예측해보자.
      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는 클릭 당 1씩 증가한다.
        • 위와 같이 state를 설정하면 다음 렌더링에 대해서만 변경된다.
        • 첫 번째 렌더링에서 number는 0이었다.
        • 따라서 해당 렌더링의 onClick 핸들러에서 setNumber(number + 1)이 호출된 후에도 number의 값은 여전히 0이다.
      • 이 버튼의 클릭 핸들러가 React에 지시하는 작업은 아래와 같다.
        • setNumber(number + 1): number는 0이므로 setNumber(0 + 1)
          • React는 다음 렌더링에서 number를 1로 변경할 준비를 한다.
        • setNumber(number + 1): number는 0이므로 setNumber(0 + 1)
          • React는 다음 렌더링에서 number를 1로 변경할 준비를 한다.
        • setNumber(number + 1): number는 0이므로 setNumber(0 + 1)
          • React는 다음 렌더링에서 number를 1로 변경할 준비를 한다.
      • setNumber(number + 1)를 3번 호출했지만, 이 렌더링에서 이벤트 핸들러의 number는 항상 0이므로 state를 1로 3번 설정했다.
  1. 시간 경과에 따른 state
  • 아래 코드의 결과는 어떻게 될지 맞춰보자.
    • import { useState } from 'react'; export default function Counter() { const [number, setNumber] = useState(0); return ( <> <h1>{number}</h1> <button onClick={() => { setNumber(number + 5); alert(number); }}>+5</button> </> ) }
  • 이전 상태의 number가 나타나게 된다.
  • 만약 타이머를 설정한다면 어떻게 동작할까?
    • 여전히 이전 상태의 number가 나타난다.
  • React에 저장된 state는 알림이 실행될 때 변경되었을 수 있지만, 사용자가 상호작용한 시점에 state 스냅샷을 사용하는 것은 이미 예약된 것이다.
  • state 변수의 값은 이벤트 핸들러의 코드가 비동기적이라도 렌더링 내에서 절대 변경되지 않는다.
    • 이 값은 컴포넌트를 호출한React가 UI의 스냅샷을 찍을 때 고정된 값이다.