React에서 state는 컴포넌트가 동적인 데이터를 처리할 수 있게 해주는 중요한 개념이다. 특히 함수 컴포넌트에서는 Hooks를 사용하여 state를 관리한다.
React Hooks는 함수 컴포넌트 내에서 리액트의 state와 생명주기 기능을 사용할 수 있게 해주는 기능이다. Hooks는 16.8버전 이후 도입되었으며, 클래스 컴포넌트를 사용하지 않고도 컴포넌트 내부 상태 관리와 라이프 사이클 메서드를 사용할 수 있게 한다.
state는 컴포넌트 내부에서 변경 가능한 데이터를 관리하는 방법이다. state의 변경은 해당 컴포넌트와 그 자식 컴포넌트들을 다시 렌더링하게 만든다.
- 컴포넌트의 상태를 저장
- re-render 사이사이에 값이 변하지 않도록 기억
- 값이 변했을때는 컴포넌트가 다시 그려지도록 re-rendering을 트리거
useState
는 함수 컴포넌트에서 상태를 관리할 수 있게 해주는 Hook이다.
const [state, setState] = useState(initialState);
initialState
: 상태의 초기 값을 설정하는 부분이야. 처음 렌더링 될 때만 사용되고, 이후 렌더링에서는 무시돼.state
: 현재 상태 값을 나타내며, 컴포넌트 렌더링 시 이 값을 참조해 화면에 표시할 수 있어.setState
: 상태 값을 변경하기 위한 함수로, 이 함수를 호출하면 컴포넌트가 다시 렌더링돼.예시:
import React, { useState } from 'react';
//useState는 상태 관리 훅을 사용하기 위해서는 import를 해야 한다.
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
useState(0)
에서 초기값은 0으로 설정 되고, count
는 상태 변수로 화면에 표시하고 있다. setCount
는 상태를 변경하기 위한 함수로, 예시에서 버튼을 클릭시 이 함수를 호출하며 count
상태가 업데이트되고 컴포넌트가 다시 렌더링된다.
const [count, setCount] = useState(0);
참조 타입의 상태도 마찬가지로 useState
를 사용하여 관리할 수 있다.
const [todos, setTodos] = useState([{ title: '할 일 1', content: '내용 1' }]);
React에서 상태의 불변성은 매우 중요하다. 상태를 직접 수정하지 않고 새로운 객체나 배열을 생성하여 변경한다.
const [todos, setTodos] = useState([{ title: '할 일 1', content: '내용 1' }]);
const addTodo = todo => {
setTodos([...todos, todo]);
};
useState
의 설정 함수는 비동기로 동작한다. 따라서 여러 번 호출되어도 즉시 반영되지 않을 수 있다.
비동기로 이루어지는 setState
는 React의 상태 업데이트가 항상 즉시 일어나지 않기 때문에 주의가 필요하다. 예를 들어, 버튼 클릭 등의 이벤트 내에서 여러 번 상태를 업데이트할 때 문제가 발생할 수 있다.
아래 예시는 클릭한 횟수를 세는 카운터 컴포넌트다.
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
const handleIncrement = () => {
// 비동기로 동작하기 때문에 아래의 연속된 호출은 원하는 대로 동작하지 않을 수 있다.
setCount(count + 1);
setCount(count + 1);
// 예상했던 것은 count가 2 증가하는 것이지만, 실제로는 1만 증가할 수 있다.
};
return (
<div>
<p>You clicked {count} times</p>
<button onClick={handleIncrement}>Click me</button>
</div>
);
}
이 문제를 해결하기 위해, 예제에 있는 setCount
와 같은 상태 설정 함수에 함수를 인자로 전달하면, React가 자동으로 현재 상태 값을 그 함수의 첫 번째 인자로 전달해준다. 그럼 그 함수는 현재 상태를 받아 새로운 상태값을 계산하고 반환하게 할 수 있다.
const handleIncrement = () => {
setCount(prevCount => prevCount + 1);
setCount(prevCount => prevCount + 1);
// 이렇게 하면 정확히 2만큼 증가한다.
};
setState
가 비동기로 동작하는 이유는 성능 최적화 때문이다. React는 여러setState
호출을 하나의 업데이트로 모아 처리할 수 있어, 불필요한 렌더링을 방지하고 성능을 향상시킨다. 이렇게 비동기로 동작하는setState
의 특징을 이해하고 올바르게 사용하는 것이 중요하다.
리액트는 데이터 흐름이 단방향으로 이루어지는 구조다. 이를 단방향 데이터 흐름이라고 부른다. 이러한 특성은 다음과 같은 장점을 가지고 있다. 컴포넌트는 자신의 state를 자식 컨포넌트에 props로 전달할 수 있다. 모든 state로부터 파생된 UI 또는 데이터는 오직 트리구조에서 자신의 ‘아래’에 있는 컴포넌트에만 영향을 미칩니다.
단방향 데이터 흐름은 컴포넌트 간의 상호작용을 간결하고 예측 가능하게 만든다. 부모 컴포넌트에서 자식 컴포넌트로만 데이터가 흐르기 때문에, 어디서 어떻게 데이터가 변경되는지를 추적하기 더 쉽다.
데이터가 한 방향으로만 흐르면, 데이터 관리가 더욱 용이하다. 상태 변화를 추적하기 쉬워져 디버깅과 유지보수가 훨씬 간편하다.
데이터의 흐름이 한 방향이므로, 컴포넌트 간의 관계가 더욱 명확해진다. 부모 컴포넌트가 자식 컴포넌트에게 어떤 데이터를 전달하는지 명확하게 알 수 있으며, 각 컴포넌트의 역할도 분명해진다.
결론
리액트에서 state 관리는 컴포넌트가 동적인 데이터를 처리하는 중심 역할을 한다. Hooks를 통해 함수 컴포넌트 내에서도 state와 생명주기를 쉽게 관리할 수 있으며, 특히
useState
는 상태 관리의 핵심이다. 또한, 상태의 불변성 유지와setState
의 비동기 동작 방식을 이해하면 효율적인 상태 관리가 가능하다. 더불어, 리액트의 단방향 데이터 흐름은 컴포넌트 간의 관계를 명확히 하고, 데이터 추적과 관리를 용이하게 함으로써 개발자가 더 직관적이고 효과적인 개발을 할 수 있게 돕는다.