지난 여정에서는 React 컴포넌트의 두 가지 주요 형태인 함수형 컴포넌트와 클래스형 컴포넌트의 기본적인 개념을 살펴보았습니다. 특히 클래스형 컴포넌트에서는 상태(state)를 관리하고 생명주기 메서드를 활용하여 동적인 UI를 구현하는 방법을 알아보았습니다. 이제 현대 React 개발의 핵심 축을 이루는 함수형 컴포넌트로 돌아와, 함수형 컴포넌트에서 상태를 관리하는 가장 기본적인 Hook인 useState 훅에 대해 깊이 있게 파헤쳐 보겠습니다.
Hook이란 무엇일까요?
본격적으로 useState 훅에 대해 알아보기 전에, 먼저 Hook이 무엇인지 간략하게 이해하고 넘어갈 필요가 있습니다. React 16.8 버전에 처음 도입된 Hooks는 함수형 컴포넌트에서 React의 state 및 생명주기 기능과 같은 기능들을 "hook" 하여 사용할 수 있도록 해주는 함수입니다. Hooks의 등장 이전에는 상태 관리나 생명주기 관련 로직을 함수형 컴포넌트 내에서 직접 구현하는 것이 불가능했기 때문에, 이러한 기능이 필요할 때는 클래스형 컴포넌트를 사용해야 했습니다.
Hooks는 이러한 제약을 극복하고 함수형 컴포넌트에서도 상태를 관리하고 side effects를 처리하는 등 다양한 React 기능을 활용할 수 있도록 혁신적인 방법을 제시합니다. Hooks의 규칙은 몇 가지 있지만 (예: Hook은 React 함수의 최상위 레벨에서만 호출해야 함), 이를 따르면 함수형 컴포넌트만으로도 복잡하고 동적인 UI를 효율적으로 구축할 수 있게 됩니다.
useState 훅의 기본 사용법
useState 훅은 함수형 컴포넌트 내에서 상태 변수를 선언하고 관리하는 가장 기본적인 Hook입니다. 이 Hook을 사용하면 함수 내에서 "state"를 가질 수 있으며, 이 상태가 변경될 때마다 React는 해당 컴포넌트를 다시 렌더링하여 UI를 업데이트합니다.
useState 훅을 사용하려면 React로부터 import 해야 합니다.
import React, { useState } from 'react';
useState 훅을 호출하면 두 개의 값을 담은 배열이 반환됩니다.
- 현재 상태 값 (current state value): 초기 상태로 설정한 값 또는 업데이트된 최신 상태 값입니다.
- 상태 업데이트 함수 (state setter function): 이 함수를 호출하여 상태 값을 변경하고 React에게 컴포넌트의 재렌더링을 요청합니다.
useState 훅을 호출할 때에는 초기 상태 값 (initial state value)을 인자로 전달합니다. 이 초기 상태 값은 숫자, 문자열, 객체, 배열 등 어떤 JavaScript 데이터 타입이라도 될 수 있습니다.
function MyComponent() {
// 숫자 타입의 상태 변수 count, 초기값은 0
const [count, setCount] = useState(0);
// 문자열 타입의 상태 변수 name, 초기값은 "Guest"
const [name, setName] = useState("Guest");
// 객체 타입의 상태 변수 user, 초기값은 { id: 1, email: 'guest@example.com' }
const [user, setUser] = useState({ id: 1, email: 'guest@example.com' });
// 배열 타입의 상태 변수 items, 초기값은 []
const [items, setItems] = useState([]);
// ... UI 렌더링 및 이벤트 처리 로직
}
위 예시처럼 useState 훅을 여러 번 호출하여 여러 개의 독립적인 상태 변수를 함수형 컴포넌트 내에서 관리할 수 있습니다. 각 상태 변수는 고유한 상태 값과 업데이트 함수를 가집니다.
상태 업데이트하기
상태 값을 변경하려면 useState 훅이 반환하는 상태 업데이트 함수를 호출해야 합니다. 직접 상태 변수를 수정하는 것은 절대 금지되어 있습니다. React는 상태 업데이트 함수를 통해 상태가 변경되었음을 감지하고, 필요한 업데이트를 수행하여 UI를 효율적으로 다시 렌더링합니다.
상태 업데이트 함수를 호출하는 방법은 두 가지가 있습니다.
1. 새로운 상태 값을 직접 전달:
가장 일반적인 방법으로, 상태 업데이트 함수에 새로운 상태 값을 직접 인자로 전달합니다.
function Counter() {
const [count, setCount] = useState(0);
function increment() {
setCount(count + 1); // 새로운 count 값으로 업데이트
}
return (
<div>
<h1>Count: {count}</h1>
<button onClick={increment}>Increment</button>
</div>
);
}
2. 함수형 업데이트 (Functional Updates):
상태 업데이트가 이전 상태 값에 의존하는 경우 (예: 카운터 증가), 상태 업데이트 함수에 함수를 인자로 전달할 수 있습니다. 이 함수는 이전 상태 값을 인자로 받고, 새로운 상태 값을 반환해야 합니다. 이 방식은 비동기적인 상태 업데이트나 여러 번의 연속적인 상태 업데이트 시 예측 불가능한 결과를 방지하는 데 유용합니다.
function Counter() {
const [count, setCount] = useState(0);
function increment() {
setCount(prevCount => prevCount + 1); // 함수형 업데이트
}
function incrementByFive() {
// 여러 번의 업데이트를 안전하게 처리
setCount(prevCount => prevCount + 1);
setCount(prevCount => prevCount + 1);
setCount(prevCount => prevCount + 1);
setCount(prevCount => prevCount + 1);
setCount(prevCount => prevCount + 1);
}
return (
<div>
<h1>Count: {count}</h1>
<button onClick={increment}>Increment</button>
<button onClick={incrementByFive}>Increment by 5</button>
</div>
);
}
함수형 업데이트를 사용하면 React는 업데이트 함수를 큐에 넣고, 모든 업데이트가 완료된 후 최종 상태를 기반으로 한 번만 컴포넌트를 리렌더링하여 성능 최적화에도 도움이 됩니다.
간단한 useState 훅 사용 예시
이제 useState 훅을 사용하여 간단한 토글 버튼 컴포넌트를 만들어 보겠습니다.
import React, { useState } from 'react';
function ToggleButton() {
const [isOn, setIsOn] = useState(false); // 초기 상태는 꺼짐 (false)
function toggle() {
setIsOn(!isOn); // 현재 상태의 반대 값으로 업데이트
}
return (
<button onClick={toggle}>
{isOn ? 'ON' : 'OFF'}
</button>
);
}
export default ToggleButton;
위 ToggleButton 컴포넌트는 isOn이라는 boolean 타입의 상태 변수를 useState(false)를 통해 선언하고, setIsOn이라는 상태 업데이트 함수를 함께 얻습니다. 버튼을 클릭하면 toggle 함수가 호출되어 setIsOn(!isOn)을 통해 isOn 상태 값을 반전시킵니다. 상태가 변경될 때마다 컴포넌트가 다시 렌더링되어 버튼의 텍스트가 "ON"과 "OFF" 사이를 전환하게 됩니다.
객체 상태 업데이트 시 주의사항
객체 타입의 상태를 업데이트할 때는 불변성 (immutability)을 유지하는 것이 중요합니다. 즉, 기존 객체를 직접 수정하는 대신, 기존 객체의 복사본을 만들고 필요한 속성만 변경한 후 새로운 객체로 상태를 업데이트해야 합니다. 이는 React가 상태 변화를 감지하고 효율적으로 업데이트를 수행하는 데 필수적인 규칙입니다.
import React, { useState } from 'react';
function ProfileEditor() {
const [user, setUser] = useState({ name: 'Guest', age: 20 });
function updateName(event) {
setUser({ ...user, name: event.target.value }); // 스프레드 연산자를 사용하여 기존 객체 복사 후 name 속성만 변경
}
function updateAge() {
setUser({ ...user, age: user.age + 1 }); // 스프레드 연산자를 사용하여 기존 객체 복사 후 age 속성만 변경
}
return (
<div>
<h2>Profile Editor</h2>
<p>Name: {user.name}</p>
<p>Age: {user.age}</p>
<input type="text" value={user.name} onChange={updateName} />
<button onClick={updateAge}>Increment Age</button>
</div>
);
}
export default ProfileEditor;
위 예시에서 updateName 함수는 스프레드 연산자 (...user)를 사용하여 기존 user 객체의 모든 속성을 복사한 새로운 객체를 생성하고, name 속성만 이벤트에서 얻은 새로운 값으로 덮어씁니다. updateAge 함수도 마찬가지로 기존 user 객체를 복사한 후 age 속성만 증가시킨 새로운 객체로 상태를 업데이트합니다.
마무리하며
이번 블로그에서는 함수형 컴포넌트에서 상태를 관리하는 가장 기본적인 Hook인 useState 훅에 대해 자세히 알아보았습니다. useState 훅의 기본적인 사용법부터 상태 업데이트 방식, 그리고 객체 상태 업데이트 시 주의해야 할 불변성 유지의 중요성까지 이해하셨으리라 생각합니다.
useState 훅은 함수형 컴포넌트에 동적인 동작과 상호작용성을 부여하는 데 필수적인 도구입니다. 앞으로 React 개발을 진행하면서 useState 훅을 능숙하게 활용하여 다양한 UI 기능을 구현할 수 있도록 꾸준히 연습하는 것이 중요합니다.
다음 블로그에서는 컴포넌트 간에 데이터를 효율적으로 전달하고 공유하는 또 다른 중요한 개념인 Props 심화에 대해 더 깊이 있게 다루어볼 예정입니다. 다양한 props 활용 방법과 컴포넌트 간의 데이터 흐름을 이해하는 시간을 갖도록 하겠습니다.
useState 훅의 세계를 함께 탐험해 주셔서 감사합니다!
'IT Data 분석' 카테고리의 다른 글
Props 심화: 컴포넌트 간 효율적인 데이터 흐름 구축 (0) | 2025.05.10 |
---|---|
React 컴포넌트 기초 (클래스형 컴포넌트): 상태 관리와 생명주기 (0) | 2025.05.07 |
React 컴포넌트 (함수형 컴포넌트): UI 구축의 기본 단위 (0) | 2025.05.04 |
JSX 이해: React UI 렌더링의 핵심에 대해 알아볼까요? (0) | 2025.05.04 |
React 시작하기: 웹 개발의 새로운 가능성을 열다 (0) | 2025.05.03 |