[React] useState의 동작 원리

Rachel·2024년 8월 11일
0

React

목록 보기
3/3
post-thumbnail

useState

useState는 React에서 함수형 컴포넌트에서 상태(state)를 관리하기 위해 제공되는 훅(Hook)입니다. 이 훅은 함수형 컴포넌트 내에서 상태를 정의하고, 그 상태를 업데이트하는 방법을 제공합니다. 아래에서 useState의 동작 원리, 개념, 클로저, 비동기 호출 등과 관련된 내용을 설명하겠습니다.

1. useState의 개념과 사용 이유

개념

  • useState는 상태를 관리하는 Hook: 함수형 컴포넌트에서 상태를 추가할 수 있도록 하는 React의 Hook입니다. 상태는 컴포넌트가 렌더링될 때 유지되는 값으로, 컴포넌트 내에서 동적인 데이터를 다룰 때 사용됩니다.
  • 상태의 정의 및 초기화: useState는 초기 상태 값을 인자로 받아, 현재 상태 값과 그 상태를 업데이트하는 함수를 반환합니다. const [state, setState] = useState(initialValue); 형태로 사용됩니다.
  • 상태의 유지: 컴포넌트가 렌더링될 때마다 useState가 반환하는 상태 값은 매번 새롭게 정의되지 않고, 이전 렌더링에서 설정된 상태가 유지됩니다.

사용 이유

  • UI 업데이트 관리: 상태가 변경되면 컴포넌트는 해당 상태를 기반으로 UI를 다시 렌더링합니다. useState를 사용해 상태를 관리함으로써, UI와 데이터의 일관성을 유지할 수 있습니다.
  • 함수형 컴포넌트에서 상태 관리: 함수형 컴포넌트는 기존 클래스형 컴포넌트와 달리 this.state를 사용할 수 없습니다. useState를 통해 함수형 컴포넌트에서도 상태를 관리할 수 있게 됩니다.

2. 클로저와 useState

클로저함수와 그 함수가 선언될 때의 렉시컬 환경(Lexical Environment)을 기억하는 메커니즘입니다. useState와 클로저는 밀접하게 관련되어 있습니다.

  • 클로저와 상태 유지: useState로 생성된 상태와 이를 변경하는 함수는 클로저에 의해 상태값을 기억합니다. 함수형 컴포넌트가 여러 번 렌더링 되더라도, 클로저를 통해 useState의 상태는 항상 최신 상태를 유지합니다. 이는 상태 관리가 컴포넌트 내에서 안정적으로 이루어질 수 있게 해줍니다.

  • 업데이트 함수와 클로저: setState와 같은 상태 업데이트 함수는 클로저를 통해 이전 상태 값을 참조하여 새로운 상태를 계산하거나, 업데이트된 상태를 렌더링 주기에 전달합니다. 이 때문에 setState에 상태를 업데이트하는 콜백 함수를 넘길 수 있습니다. 예를 들어:

    const [count, setCount] = useState(0);
    
    const increment = () => {
      setCount((prevCount) => prevCount + 1);
    };

이 경우, setCount의 인자로 넘겨지는 함수는 prevCount라는 이름으로 이전 상태값을 가지고 있으며, 이 값은 클로저에 의해 유지됩니다.

3. 비동기 호출과 useState

useState에서의 상태 업데이트는 비동기적으로 처리됩니다.

  • 상태 업데이트의 비동기성: setState는 즉각적으로 상태를 변경하지 않습니다. React는 여러 상태 업데이트를 하나의 렌더링 주기(batch)에서 처리하여 성능을 최적화합니다. 따라서 setState를 호출한 직후에 상태 값을 참조하면 업데이트되기 전의 값이 반환될 수 있습니다.

  • 비동기 로직에서의 상태 관리: 비동기 작업(예: API 호출)에서 useState를 사용해 상태를 관리할 때, 비동기 작업이 완료된 후 상태를 업데이트할 수 있습니다. 이러한 경우 useEffect와 같은 훅을 함께 사용하여 비동기 로직을 처리할 수 있습니다.

useEffect(() => {
  async function fetchData() {
    const data = await fetchSomeData();
    setState(data);
  }
  fetchData();
}, []);

자세히 정리

useState의 비동기적 특성

  • 비동기적 상태 업데이트: React에서 useState를 통해 상태를 업데이트할 때, 상태 업데이트는 즉각적으로 반영되지 않습니다. 대신, React는 상태 변경 요청을 큐에 넣어두고, 컴포넌트가 다시 렌더링될 때 이 큐에 담긴 상태 업데이트를 한꺼번에 처리합니다.
  • 동기화 문제 방지: useState가 비동기적으로 동작하는 이유 중 하나는 여러 상태 변경이 일어날 때마다 컴포넌트를 여러 번 재렌더링하지 않기 위해서입니다. 즉, 여러 상태 변경이 발생해도 React는 성능을 최적화하기 위해 이러한 변경 사항을 한꺼번에 처리합니다.
  • 렌더링 이후 상태 반영: setState를 호출한 후 바로 그 다음 줄에서 상태를 확인하면, 여전히 이전 상태 값이 반환됩니다. 이는 상태가 바로 업데이트되지 않기 때문입니다. 상태가 업데이트된 후에야 그 값이 변경되며, 이 변경은 다음 렌더링 사이클에서 반영됩니다.

React의 배치 업데이트(batch update) 메커니즘

  • 배치 업데이트: React는 상태 업데이트가 발생할 때마다 즉각적으로 컴포넌트를 다시 렌더링하지 않습니다. 대신 여러 개의 상태 업데이트가 발생하면, 이를 배치(batch)로 묶어서 한 번의 렌더링 사이클에서 모두 처리합니다. 이렇게 하면 불필요한 재렌더링을 줄여 성능을 최적화할 수 있습니다.
  • 동시성 모드와 배치 업데이트: React 18부터 도입된 동시성 모드(Concurrent Mode)에서는 배치 업데이트가 기본적으로 활성화됩니다. 이 모드에서는 여러 개의 상태 업데이트가 자동으로 배치되어 처리됩니다. 예를 들어, 여러 개의 setState 호출이 있을 때 이들은 모두 배치로 묶여서 처리되고, 그 결과 컴포넌트는 한 번만 렌더링됩니다.

useState의 비동기성 + 배치 업데이트의 결합

  • 발생할 수 있는 문제

    • 실시간 상태 확인 어려움: useState가 비동기적으로 동작하면서 배치 업데이트가 적용되면, 상태 업데이트가 일어난 직후에 상태를 확인할 때, 이는 아직 최신 값으로 반영되지 않았을 수 있습니다. 이는 상태 업데이트가 배치로 처리되면서, 그 사이에 발생하는 여러 상태 변경이 함께 묶여 다음 렌더링에서 처리되기 때문입니다.
    • 최적화와 예측 가능성: React는 이 배치 업데이트 메커니즘을 통해 최적화를 이루지만, 이로 인해 개발자가 상태 업데이트의 타이밍을 정확하게 예측하기 어려운 경우가 생깁니다. 특히 상태 값에 의존하는 로직을 바로 상태 업데이트 이후에 실행하려고 할 때, 비동기적 특성으로 인해 예상치 못한 동작이 발생할 수 있습니다.
  • 해결 방법

    • 상태 값 의존 로직의 분리: 상태 업데이트 후 상태 값을 직접 참조하지 않고, 상태 변경에 의존하는 로직을 가능한 한 분리하거나, 업데이트 함수의 콜백 기능을 사용해 안전하게 처리하는 방법도 있습니다.
    • useEffect 활용: 상태 값이 변경된 이후에 특정 작업을 수행하려면 useEffect를 사용하여 상태 값의 변경을 감지하고, 그에 따라 로직을 실행할 수 있습니다. 이는 상태 값이 업데이트된 이후에 원하는 동작을 보장할 수 있는 방법입니다.

실제 트러블슈팅 경험

프로젝트시 useState의 비동기적 특성과 배치 업데이트에 대한 이해가 부족해 setState()로 상태를 설정하고 그 상태를 다음 줄에서 바로 확인하려고 해 문제가 발생한 경험이 있었습니다. 참고

당시에는 useState의 비동기적 특성을 이해하고 문제를 해결하였습니다. 이후 공부를 더 하며 배치 업데이트와 연관된 점을 파악했고, useState의 동작원리를 더 깊이 공부하며 클로저를 이용해 이전 상태를 참조할 수 있음을 알게되었습니다.

처음 React를 공부할 때는 함수형 컴포넌트에서 간단하게 상태 관리할 수 있는 Hook으로만 이해했지만 해당 경험을 통해 동작원리를 잘 알지 못하면 버그를 발생시킬 수 있다는 점을 배웠습니다.


정리
useState는 React에서 함수형 컴포넌트의 상태를 관리하기 위한 핵심적인 도구입니다. 클로저와의 결합을 통해 상태를 안전하게 관리할 수 있으며, 비동기 작업과 함께 사용할 때 상태 관리의 복잡성을 처리할 수 있습니다. 이러한 특징들은 React 컴포넌트가 복잡한 UI를 효율적으로 관리할 수 있도록 돕습니다.

React 공식 문서 - useSTate


추가하면 좋은 부분이나 잘못된 점이 있다면 댓글 남겨주세요. 감사합니다 :)

profile
기존 블로그: https://hi-rachel.tistory.com

0개의 댓글