상태가 필요한 이유
사용자가 버튼을 누르거나 입력 필드에 텍스트를 추가할 때, 컴포넌트는 그 변화를 기억하고 UI에 반영해야 합니다. 예를 들어, 체크리스트에서 항목을 선택하거나, 탭 메뉴에서 활성 탭을 전환할 때, 단순 변수로는 이를 유지할 수 없습니다. 상태(state)는 이런 데이터를 저장하고, 변경 시 컴포넌트를 자동으로 업데이트하는 역할을 합니다.
useState로 상태 선언하기
useState는 상태 변수와 그 값을 업데이트하는 함수를 쌍으로 반환합니다. 상태가 변경되면 React는 컴포넌트를 재렌더링해 최신 상태를 반영합니다.
import { useState } from 'react';
export default function TogglePanel() {
const [isOpen, setIsOpen] = useState(false);
function handleToggle() {
setIsOpen(!isOpen);
}
return (
<div style={{ padding: '15px', border: '1px solid #ddd', borderRadius: '5px' }}>
<button
onClick={handleToggle}
style={{ marginBottom: '10px', padding: '5px 10px' }}
>
{isOpen ? '패널 닫기' : '패널 열기'}
</button>
{isOpen && (
<div style={{ backgroundColor: '#f9f9f9', padding: '10px' }}>
<h3>숨겨진 콘텐츠</h3>
<p>이 내용은 패널이 열려 있을 때만 표시됩니다.</p>
</div>
)}
</div>
);
}
- useState(false): isOpen의 초기값을 false로 설정합니다.
- setIsOpen: 이 함수는 isOpen를 업데이트하며, 새로운 값이 설정되면 컴포넌트를 다시 렌더링합니다.
다중 상태 변수 활용
하나의 컴포넌트에서 여러 가지 데이터를 기억할 필요가 있을 때, useState를 여러 번 호출할 수 있습니다. 상태가 서로 관련이 없을 경우, 각각 분리하여 관리하는 것이 더 명확하고 유지보수가 용이합니다.
import { useState } from 'react';
export default function TaskTracker() {
const [tasksCompleted, setTasksCompleted] = useState(0);
const [totalTasks, setTotalTasks] = useState(3);
function handleCompleteTask() {
if (tasksCompleted < totalTasks) {
setTasksCompleted(tasksCompleted + 1);
}
}
function handleAddTask() {
setTotalTasks(totalTasks + 1);
}
return (
<div style={{ padding: '20px', border: '1px solid #eee', maxWidth: '400px' }}>
<h2>작업 추적기</h2>
<p>완료된 작업: {tasksCompleted} / 총 작업: {totalTasks}</p>
<button
onClick={handleCompleteTask}
style={{ marginRight: '10px', padding: '5px 10px' }}
>
작업 완료
</button>
<button
onClick={handleAddTask}
style={{ padding: '5px 10px' }}
>
작업 추가
</button>
</div>
);
}
컴포넌트에 국한된 메모리
상태는 해당 컴포넌트 인스턴스에만 존재하며, 동일한 컴포넌트를 여러 번 렌더링하면 각 인스턴스는 독립적인 상태를 갖게 됩니다. 이는 상태가 외부와 격리되어 데이터 충돌을 방지한다는 뜻입니다.
import TaskTracker from './TaskTracker';
export default function App() {
return (
<div style={{ display: 'flex', gap: '20px', padding: '20px' }}>
<TaskTracker />
<TaskTracker />
</div>
);
}
- 두 개의 TaskTracker 컴포넌트는 각자의 tasksCompleted와 totalTasks를 관리합니다.
- 한 인스턴스의 상태 변경이 다른 인스턴스에 영향을 주지 않습니다.
- 공유가 필요할 경우 상태를 부모로 올려 props로 전달해야 합니다.
상태와 로컬 변수의 차이
- 로컬 변수는 함수 호출 간 유지되지 않고, 변경 시 재렌더링을 유발하지 않습니다.
- 상태는 React가 관리하며, 값이 바뀌면 UI를 새로 그립니다.
로컬 변수
export default function WrongExample() {
let count = 0; // 로컬 변수
function handleClick() {
count += 1; // 값은 변하지만 UI는 갱신되지 않음
console.log(count);
}
return <button onClick={handleClick}>클릭: {count}</button>;
}
useState로 상태 관리
export default function CorrectExample() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(count + 1)}>클릭: {count}</button>;
}
상태 관리 주의 사항
- 최소화: 불필요한 상태 선언을 피하고, 파생된 값은 계산으로 처리합니다.
- 객체 사용: 관련된 데이터를 하나의 상태로 묶어서 관리합니다.
- 상태 업데이트가 잦으면 useReducer 또는 메모이젱션을 고려합니다.
'REACT > 리액트 학습하기' 카테고리의 다른 글
[REACT] state의 스냅샷 이해하기 (0) | 2025.03.14 |
---|---|
[REACT] 렌더링과 커밋 과정: 화면에 나타나기까지의 3단계 (0) | 2025.03.14 |
[REACT] 이벤트 핸들링 기법 (0) | 2025.03.14 |
[REACT] UI 트리 이해하기 (0) | 2025.03.13 |
[REACT] 컴포넌트의 최적화와 확장 (0) | 2025.03.13 |