
React – 상태 관리와 Hooks – State와 Props – 2 – 부모-자식 간 데이터 흐름
안녕하세요! 😄
이번 시간에는 React의 가장 핵심적인 개념 중 하나인 부모-자식 간 데이터 흐름에 대해 자세히 알아보겠습니다.
React에서는 데이터를 어떻게 전달하고, 그 흐름을 어떻게 관리해야 할까요?
React의 데이터 흐름은 마치 폭포수처럼 위에서 아래로 흘러내리는 구조를 가지고 있어요.
이 구조를 잘 이해하고 활용하면, 예측 가능한 컴포넌트 구조를 만들 수 있답니다!
1. React의 데이터 흐름: 단방향 바인딩
React의 기본 철학 중 하나는 **단방향 데이터 흐름(one-way data flow)**입니다.
즉, 부모 컴포넌트가 자식 컴포넌트에게 데이터를 전달하고, 자식은 그 데이터를 “받기만” 해요.
🔁 자식이 부모에게 직접 데이터를 수정하거나 영향을 주는 일은 없어요.
💬 대신, 부모가 “수정할 수 있는 함수”를 props로 내려주고, 자식이 그것을 호출하는 식으로 협업해요!
2. 가장 기본적인 데이터 흐름 예시
function Child({ message }) {
return <p>전달받은 메시지: {message}</p>;
}
function Parent() {
return <Child message="안녕하세요, React!" />;
}
Parent
는Child
에게message
라는 데이터를 전달합니다.Child
는 해당 props를 이용해 화면에 출력할 뿐, 변경은 하지 않아요.
3. 자식 → 부모로 데이터를 전달하고 싶다면?
직접적으로는 불가능하지만, 함수를 props로 내려주면 가능해요.
💡 예시: 자식에서 버튼을 클릭하면 부모의 state 변경
function Child({ onIncrease }) {
return <button onClick={onIncrease}>점수 증가</button>;
}
function Parent() {
const [score, setScore] = useState(0);
const increaseScore = () => {
setScore(prev => prev + 1);
};
return (
<div>
<p>현재 점수: {score}</p>
<Child onIncrease={increaseScore} />
</div>
);
}
👇 흐름 설명
- 부모
Parent
는 점수(score
)라는 상태를 갖고 있고, - 자식
Child
는 버튼 클릭 시 부모의increaseScore
함수를 호출함으로써 - 자식 → 부모로 이벤트를 전달하는 구조가 됩니다!
4. 중첩된 컴포넌트 구조에서도 가능할까요?
물론이죠! 여러 컴포넌트가 중첩된 구조에서도 계단식으로 props를 전달하면 동일하게 동작합니다.
function Button({ onClick }) {
return <button onClick={onClick}>Click me!</button>;
}
function Panel({ onAction }) {
return <div><Button onClick={onAction} /></div>;
}
function App() {
const handleAction = () => alert('버튼이 눌렸어요!');
return <Panel onAction={handleAction} />;
}
- 이 예시에서는
App → Panel → Button
으로 함수가 props로 전달되고, - 최종적으로 Button이 클릭되면
App
의 로직이 실행됩니다.
5. props로 상태도 전달 가능
function Display({ count }) {
return <h2>현재 카운트: {count}</h2>;
}
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<Display count={count} />
<button onClick={() => setCount(count + 1)}>+1</button>
</div>
);
}
➡️ count
는 부모인 Counter
에서 정의된 상태지만,
자식인 Display
가 그대로 받아서 보여줄 수 있어요.
🧠 중요한 점은 상태의 주인은 부모이고,
자식은 props를 통해 상태값을 사용할 수 있을 뿐, 직접 수정은 불가하다는 것입니다.
6. 데이터 흐름 정리 (시각적 표현)
[부모 컴포넌트]
↓ props
[자식 컴포넌트]
↓ props
[손자 컴포넌트]
- 상태(state)는 상위 컴포넌트에서 정의
- 자식 컴포넌트에게는 props로 값 또는 함수 전달
- 자식은 함수를 호출해서 간접적으로 상태 변경 가능
7. 데이터 흐름을 분리하는 팁 (Smart vs Dumb 컴포넌트)
타입 | 설명 | 역할 |
---|---|---|
Smart 컴포넌트 | 상태와 로직을 가짐 | API 호출, 상태 관리 등 |
Dumb 컴포넌트 | props만 받음 | UI 출력만 담당 |
💡 예시
// Dumb 컴포넌트
function UserCard({ name, onClick }) {
return <button onClick={onClick}>이름: {name}</button>;
}
// Smart 컴포넌트
function UserList() {
const handleClick = () => alert('사용자 클릭됨!');
return <UserCard name="영희" onClick={handleClick} />;
}
➡️ 이렇게 역할을 나누면 유지보수가 쉬운 컴포넌트 구조가 만들어져요!
8. props가 너무 깊어질 때는?
컴포넌트가 너무 깊게 중첩되면 props 전달이 복잡해질 수 있어요.
이런 경우에는 Context API
를 사용하거나, 전역 상태 관리 도구를 사용하는 것을 고려해야 해요.
하지만 지금 단계에서는 단방향 흐름과 props 전달만으로도 충분히 복잡한 UI를 구성할 수 있답니다. 😉
9. 주의할 점 요약
항목 | 주의사항 |
---|---|
props는 부모 → 자식으로만 흐름 | 반대 방향은 함수 props로 처리 |
props는 읽기 전용 | 자식에서 직접 수정 ❌ |
상태는 소유자가 관리 | 변경은 상태가 있는 컴포넌트에서만 |
중첩 컴포넌트는 props 전달 반복 | 너무 깊어지면 Context 고려 |
Smart / Dumb 컴포넌트 분리 | 역할 분리로 코드 가독성 향상 |
마무리하며
React에서 데이터 흐름은 “위에서 아래로” 흐른다는 원칙을 잘 이해하는 것이 중요해요.
이 원칙만 잘 지켜도 버그가 줄고, 협업이 쉬워지며, 컴포넌트 재사용성도 높아집니다.
다음 시간에는 이 흐름을 바탕으로 state와 props를 조합해서 동적인 UI를 어떻게 만들어낼 수 있는지,
또 props를 통해 컴포넌트를 얼마나 유연하게 재사용할 수 있는지에 대해 더 실전적인 예제로 배워볼게요! 🎯
React는 흐름만 이해해도 반은 성공이에요! 계속해서 함께 배워봐요! 🚀