본문 바로가기
React

[React] State

by goblin- 2024. 9. 13.

**state**는 리액트에서 컴포넌트의 상태를 나타내는 객체로, 컴포넌트의 동적인 데이터를 관리하고, 이 데이터가 변경될 때 컴포넌트를 다시 렌더링하는 역할을 합니다. state는 리액트 컴포넌트가 변경 가능한 값을 관리할 수 있도록 하며, 리액트의 핵심 개념 중 하나입니다.

 

1. state의 기본 개념

 

**state**는 컴포넌트가 유지하고 있는 내부 데이터를 의미하며, 이 데이터는 시간이 지나면서 또는 사용자 상호작용에 따라 변경될 수 있습니다.

state동적인 값을 저장하고, 그 값이 변경될 때마다 해당 컴포넌트와 그 자식 컴포넌트들이 자동으로 다시 렌더링됩니다.

state는 컴포넌트 내부에서 관리되는 지역 상태이므로, 같은 컴포넌트 내에서만 사용할 수 있고 다른 컴포넌트와 직접적으로 공유되지 않습니다. 부모 컴포넌트나 외부로부터 전달받는 props와는 달리 컴포넌트 내부에서만 관리됩니다.

 

2. 함수형 컴포넌트에서의 state 관리: useState 훅

 

함수형 컴포넌트에서는 useState라는 리액트 훅을 사용해 상태를 관리합니다. useState 훅은 상태값과 해당 상태를 업데이트하는 함수를 반환합니다.

 

useState 기본 사용법:

import React, { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0); // 상태 초기값은 0

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}

설명:

 

useState(0): useState는 상태의 초기값을 받습니다. 이 예시에서는 0을 초기값으로 설정했습니다.

[count, setCount]: useState는 배열을 반환합니다. 첫 번째 요소는 현재 상태(count), 두 번째 요소는 상태를 업데이트하는 함수(setCount)입니다.

상태 업데이트: setCount 함수를 호출하면 리액트가 상태를 업데이트하고, 컴포넌트는 다시 렌더링됩니다. 위 예시에서는 버튼을 클릭할 때마다 count가 1씩 증가하고, 그에 따라 UI가 업데이트됩니다.

 

3. state의 특징

 

1) 초기 상태

 

상태는 useState를 호출할 때 전달된 초기값으로 설정됩니다. 이 초기값은 컴포넌트가 처음 렌더링될 때만 사용되며, 이후로는 setState 함수로 상태를 변경합니다.

 

2) 상태 변경 시 리렌더링

 

상태가 변경되면 리액트는 해당 컴포넌트를 다시 렌더링합니다. 이때 리액트는 변경된 상태를 반영한 새로운 UI를 렌더링하고, 변경된 부분만 업데이트합니다.

function Example() {
  const [text, setText] = useState('Hello');

  return (
    <div>
      <p>{text}</p>
      <button onClick={() => setText('Goodbye')}>Change Text</button>
    </div>
  );
}

위 코드에서 버튼을 클릭하면 text 상태가 “Goodbye”로 변경되고, UI가 다시 렌더링되어 텍스트가 업데이트됩니다.

 

3) 상태는 비동기적으로 업데이트

 

리액트는 성능 최적화를 위해 여러 상태 업데이트를 비동기적으로 처리할 수 있습니다. 연속된 상태 변경 요청은 리액트가 일괄 처리하여 한 번에 업데이트될 수 있습니다.

function Example() {
  const [count, setCount] = useState(0);

  const handleClick = () => {
    setCount(count + 1);
    setCount(count + 2);
  };

  return <button onClick={handleClick}>Increment</button>;
}

위 코드에서 setCount가 두 번 호출되지만, 리액트는 이를 일괄 처리하여 한 번만 렌더링할 수 있습니다. 상태 변경은 비동기적으로 처리되어 성능을 최적화합니다.

 

4) 불변성 유지

 

리액트에서 상태는 불변성을 유지해야 합니다. 즉, 기존 상태를 직접 변경하지 않고 새로운 상태를 생성하여 업데이트해야 합니다. 이는 리액트가 상태 변경을 감지하고, 적절히 컴포넌트를 다시 렌더링하기 위함입니다.

function Example() {
  const [items, setItems] = useState([1, 2, 3]);

  const addItem = () => {
    setItems([...items, 4]); // 상태를 복사한 후 새 아이템을 추가
  };

  return (
    <div>
      {items.map(item => <p key={item}>{item}</p>)}
      <button onClick={addItem}>Add Item</button>
    </div>
  );
}

 

4. state와 props의 차이

 

**state**는 컴포넌트 내부에서 관리되며, 동적인 데이터를 저장하고 관리하는 데 사용됩니다. 컴포넌트의 상태는 컴포넌트 자체에서 관리하며, 변경될 수 있습니다.

**props**는 부모 컴포넌트가 자식 컴포넌트에게 전달하는 데이터입니다. props읽기 전용이며, 자식 컴포넌트에서는 변경할 수 없습니다.

 

비교:

특성 state props
변경 가능 여부 컴포넌트 내에서 변경 가능 부모로부터 전달, 변경 불가
데이터 소유 컴포넌트 자체가 소유 부모 컴포넌트에서 전달됨
초기화 방식 useState로 초기화 부모 컴포넌트에서 설정한 값 전달

 

5. 상태 관리의 패턴

 

컴포넌트 간 상태를 공유해야 할 때는 상태를 상위 컴포넌트로 끌어올려 상위 컴포넌트에서 상태를 관리하고, 그 상태를 props로 하위 컴포넌트에 전달하는 방식으로 처리합니다. 이 방식으로 여러 컴포넌트가 동일한 상태를 공유할 수 있습니다.

 

상태 끌어올리기 예시:

function Parent() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <Child count={count} onIncrement={() => setCount(count + 1)} />
    </div>
  );
}

function Child(props) {
  return (
    <div>
      <p>Count: {props.count}</p>
      <button onClick={props.onIncrement}>Increment</button>
    </div>
  );
}

부모 컴포넌트에서 상태(count)를 관리하고, 그 상태를 자식 컴포넌트에 props로 전달하여 자식 컴포넌트에서 상태를 사용할 수 있게 합니다.

자식 컴포넌트에서 콜백 함수를 호출하여 부모의 상태를 업데이트할 수 있습니다.

 

결론

 

함수형 컴포넌트에서 state는 컴포넌트의 동적인 데이터를 관리하고, 상태가 변경될 때마다 UI를 자동으로 다시 렌더링하는 중요한 개념입니다.

useState 훅을 사용하여 상태를 정의하고, 상태 업데이트 함수로 상태를 변경할 수 있습니다.

상태는 직접 수정할 수 없으며, 반드시 setter 함수를 통해 변경해야 합니다.

state는 각 컴포넌트 내에서 관리되는 독립적인 데이터이지만, 상위 컴포넌트를 통해 여러 컴포넌트 간 상태를 공유할 수 있습니다.