
React – 상태 관리와 Hooks – State와 Props – 0 – State 정의 및 변경 (불변성 원칙)
안녕하세요! 😄
오늘은 React에서 컴포넌트의 내부 상태를 관리하는 핵심 개념, 바로 **State(상태)**에 대해 깊이 알아볼게요.
또한 React의 핵심 철학 중 하나인 **불변성(immutability)**에 대해서도 함께 살펴볼 거예요.
여러분이 만든 컴포넌트가 사용자와 상호작용하며 동적으로 변해야 한다면?
그 중심에는 항상 state가 있어요!
1. State란 무엇인가요?
State는 컴포넌트 내부에서 데이터를 저장하고 관리하는 공간이에요.
비유하자면, state는 컴포넌트의 기억력이에요.
버튼을 몇 번 눌렀는지, 입력창에 어떤 텍스트가 써졌는지 기억해야 하잖아요?
그걸 state가 대신 기억해주는 거랍니다.
2. State vs Props 비교
항목 | props | state |
---|---|---|
데이터 소유자 | 부모 컴포넌트 | 자신(자식) 컴포넌트 |
수정 가능 여부 | 읽기 전용 | 수정 가능 |
역할 | 외부에서 전달되는 데이터 | 내부에서 변화하는 데이터 |
사용 목적 | 전달과 구성 | 동적인 UI 관리 |
3. useState 훅을 이용한 상태 정의
React에서 상태는 **useState
라는 훅(Hook)**을 이용해서 정의합니다.
import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0); // count의 초기값은 0
return (
<div>
<p>현재 카운트: {count}</p>
<button onClick={() => setCount(count + 1)}>증가</button>
</div>
);
}
설명
useState(0)
→ 초기값 0으로 상태 생성count
→ 상태 값setCount
→ 상태를 변경하는 함수
useState
를 사용하면 컴포넌트는 상태를 기억하고, 값이 변경되면 자동으로 다시 렌더링돼요!
4. 상태는 직접 수정하면 안 돼요 ❌
count = count + 1; // ❌ 절대 이렇게 직접 변경하지 마세요!
React는 상태가 바뀌는 순간을 감지해야만, 컴포넌트를 다시 그려줄 수 있어요.
setCount
처럼 전용 함수를 사용하지 않으면, 화면에 반영이 안 됩니다.
5. 상태 변경의 예시: 텍스트 입력
function InputField() {
const [text, setText] = useState('');
return (
<div>
<input
type="text"
value={text}
onChange={(e) => setText(e.target.value)}
/>
<p>입력한 값: {text}</p>
</div>
);
}
- 입력창에 텍스트를 입력하면
text
라는 상태가 갱신되며, setText
가 호출되고, 컴포넌트가 다시 그려집니다.
6. 불변성이 중요한 이유
불변성이란 한번 만들어진 데이터는 직접 수정하지 않고, 새로운 값을 만들어서 교체하는 것이에요.
const arr = [1, 2, 3];
const newArr = [...arr, 4]; // ✅ 새로운 배열 생성 (불변성 유지)
❌ 불변성을 깨뜨리는 예
arr.push(4); // 원본 배열 직접 수정 → React가 감지하지 못할 수 있음!
✅ 불변성을 지키는 예
const newArr = [...arr, 4]; // 새로운 배열 생성
React는 이전 상태와 새로운 상태를 비교하여 변화 여부를 판단하는데,
불변성을 지키지 않으면 변화를 감지하지 못하고 렌더링도 안 될 수 있어요!
7. 객체 상태 업데이트 예시
function Profile() {
const [user, setUser] = useState({ name: '철수', age: 25 });
const increaseAge = () => {
setUser({ ...user, age: user.age + 1 });
};
return (
<div>
<p>이름: {user.name}</p>
<p>나이: {user.age}</p>
<button onClick={increaseAge}>나이 증가</button>
</div>
);
}
setUser
호출 시 객체 전체를 새로 만들되,...user
를 통해 기존 데이터는 복사하고,- 변경할 부분만 덮어씌우는 패턴입니다.
8. 불변성 유지하는 패턴 모음
상황 | 방법 |
---|---|
배열 추가 | setItems([...items, newItem]) |
배열 제거 | setItems(items.filter(i => i.id !== 삭제ID)) |
배열 수정 | setItems(items.map(i => i.id === 수정ID ? {...i, 변경내용} : i)) |
객체 업데이트 | setState({...state, 변경속성: 값}) |
9. 상태 변경은 비동기! 주의사항
setCount(count + 1);
setCount(count + 1); // ❌ 의도와 달리 1만 증가할 수 있어요!
이럴 땐 함수형 업데이트를 사용해야 해요:
setCount(prev => prev + 1);
setCount(prev => prev + 1); // ✅ 이렇게 하면 2만큼 증가!
10. 주의할 점 요약
항목 | 설명 |
---|---|
useState 는 배열 구조 분해로 사용 |
[value, setValue] = useState() |
상태 직접 수정 금지 | setXxx() 함수로만 변경 |
상태 변경 시 새로운 객체/배열 생성 | ... , filter , map 등으로 불변성 유지 |
상태 변경은 비동기 | 연속 호출 시 prev => 방식 사용 |
상태 변경이 일어나면 자동 렌더링 | 화면이 자동으로 갱신됨 |
마무리하며
React에서 state는 컴포넌트의 생명력입니다!
이 state를 불변성 원칙에 따라 신중하게 다루는 습관이 쌓이면,
나중에 리팩토링, 디버깅, 성능 최적화까지 한층 수월해질 거예요. 💪
다음 글에서는 props와 state가 함께 동작하는 방식,
그리고 상태를 여러 컴포넌트 간에 어떻게 공유하고 분리하는지에 대해서도 더 깊이 배워볼게요!
🔥 한 걸음 더 성장한 React 개발자가 되어봅시다!