React 스터디 기록 #4 - 컴포넌트 상태

정유진·2026년 2월 23일

오늘은 3주차 스터디 범위인 4장과 7장 중,
먼저 4장 ‘컴포넌트 상태’ 에 대한 개념 정리를 해보려고 합니다.


4장. 컴포넌트 상태
리액트 애플리케이션이 단순한 정적 페이지를 넘어
동적으로 변화하는 UI를 제공 할 수 있는 이유는 바로 상태 관리 덕분입니다.

이 장에서는 리액트에서 컴포넌트의 상태를 어떻게 정의하고,
어떻게 변경하며, 왜 상태로 관리해야 하는지를 살펴봅니다.




🅠 변수로 데이터를 관리하면 왜 문제가 생길까?

리액트 컴포넌트에서 데이터를 정의하는 가장 간단한 방법은
자바스크립트의 let이나 const 키워드를 사용하는 것입니다.

export default function App(){
  let name = '철수';
  const age = 20; 

  return (
    <div>
      <p>{name}</p>
      <p>{age}</p>
    </div>
  );
}

이 코드는 정상적으로 화면에 값을 출력합니다.

하지만 다음과 같이 값을 변경해보면 문제가 발생합니다.

export default function App(){
  let name = '철수';
  const age = 20;
  
  const nameChange = () => {
    name = '영희';
    console.log(name);
  };
  
  return (
    <div>
      <p>{name}</p>
      <p>{age}</p>
      <button onClick={nameChange}>이름 변경</button>
    </div>
  );
}

버튼을 클릭하면 콘솔에는 "영희"가 출력됩니다. 하지만 화면에는 여전히 "철수"가 표시됩니다.
왜 이런 일이 발생할까요?

리액트는 일반 변수의 변경을 감지하지 못하기 때문입니다.

즉, let이나 const로 선언한 변수는 값이 바뀌어도컴포넌트가 다시 렌더링되지 않습니다.


🅐 그래서 등장한 개념, 상태(state)

리액트에서는 화면에 영향을 주는 데이터는
단순한 변수가 아니라 상태(state) 로 관리해야 합니다.

컴포넌트의 상태란,

컴포넌트 내부에서 관리되는 데이터로,
사용자와의 상호작용에 따라 변경될 수 있는 값

을 의미합니다.

상태가 변경되면 리액트는 해당 컴포넌트를 자동으로 리렌더링합니다.
이 덕분에 UI가 실제 데이터 변화와 동기화됩니다.




1. 컴포넌트의 상태란?

  • 리액트에서 상태(state)는 시간으니 흐름에 따라 변경되는 데이터이다.
  • 일반 변수(let 등)는 값이 바뀌어도 리렌더링이 발생하지 않는다.
  • 화면에 반영되어야 하는 값은 반드시 상태로 관리해야 한다.
  • 상태가 변경되면 리액트는 해당 컴포넌트를 자동으로 다시 렌더링한다.
  • 리렌더링은 변경된 부분만 효율적으로 반영된다.

핵심 : 화면에 영향을 주는 데이터는 상태로 관리한다.


2. userState 훅 (기본 상태 관리)

❶ userState 기본 구조

const [state, setState] = useState<Type>(initialState);
  • state : 현재 상태 값
  • setState : 상태 변경 함수
  • <Type> : useState 훅으로 정의할 상태 값의 타입을 제네릭으로 지정 (생략가능)
  • initialState : 초기값
    특징 :
  • 배열 구조 분해 할당 사용
  • setState 호출 시 리렌더링 발생

❷ 상태 변경 방법

(1) 값 직접 변경

setCount(count + 1);

(2) 함수형 업데이트 (이전 값 기반)

setCount(prev => prev + 1);

→ 연속 호출, 비동기 업데이트 상황에서는 함수형 업데이트 권장

❸ useState 동작 흐름

  1. useState로 상태 선언
  2. 이벤트 발생
  3. setState 호출
  4. 상태 변경
  5. 컴포넌트 재렌더링

❹ 여러개의 상태 관리

const [name, setName] = useState('');
const [age, setAge] = useState(0);
  • 상태는 여러 개 선언 가능
  • 각 상태는 독립적으로 관리 됨

❺ 초기값과 타입

  • 초기값이 null 인 경우 타입 명시 필요 (TypeScript)
  • 숫자, 문자열, 객체 등 다양한 타입 가능
const [user, setUser] = useState<User | null>(null);

3. 상태 관리 시 주의사항

❶ 상태는 직접 변경하지 않는다

count = count + 1setCount(count + 1)

❷ 여러번 setState 호출 시 주의

setCount(count + 1);
setCount(count + 1);

→ 기대값과 다를 수 있음
→ 함수형 업데이트 사용 권장

❸ 리액트 훅 사용 규칙

  • 컴포넌트 최상단에서만 호출
    조건문, 반복문 내부에서 호출 금지

4. 상태 끌어올리기 (State Lifting)

  • 여러 컴포넌트가 동일 상태를 공유해야 할 경우
  • 공통 부모 컴포넌트로 상태를 이동
App
 ├─ CountDisplay
 └─ CountButtons
  • 상태는 부모(App)에 위치
  • props로 하위 컴포넌트에 전달

핵심 : 상태는 가장 가까운 공통 부모에 둔다


5. 상태 관리 패턴

❶ 상태와 변경 함수를 함께 props로 전달

<Child count={count} setCount={setCount} />

❷ 변경 로직을 부모에서 정의 후 함수만 전달

const increment = () => setCount(count + 1);
<Child increment={increment} />

→ 책임 분리 측면에서 더 권장되는 방식


6. useReducer (상태 로직이 복잡할 때)

기본 구조 :

const [state, dispatch] = useReducer(reducer, initialState);

구성요소 :

  • state : 현재 상태
  • dispatch : 액션 전달 함수
  • reducer : 상태 변경 로직 함수
  • initialState : 초기 상태

특징 :

  • 상태 변경 로직을 한 곳에 모아 관리
  • 복잡한 상태 구조에 적합
  • 액션 기반 업데이트

7. 리액트 개발자 도구

  • Components 탭 → props, state 확인
  • Profiler → 렌더링 성능 분석
  • 어떤 컴포넌트가 왜 렌더링 되는지 추적 가능



4장 핵심 정리

  • 화면에 영향을 주는 값은 상태로 관리한다.
  • 상태 변경은 setState를 통해 이루어진다.
  • 상태는 공통 부모에 위치시킨다.
  • 복잡한 상태는 useReducer를 사용한다.
  • 리렌더링은 상태 변경에 의해 발생한다



이번 글에서는 4장의 핵심 개념을 정리해보았습니다.
다음 글에서는 7장 조건부 렌더링과 반복 렌더링을 정리하고,
이후 3주차 과제 구현까지 이어서 기록해보겠습니다.

profile
개발전공 대학생

0개의 댓글