React – 상태 관리와 Hooks – State와 Props – 2 – 부모-자식 간 데이터 흐름

React – 상태 관리와 Hooks – State와 Props – 2 – 부모-자식 간 데이터 흐름

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!" />;
}
  • ParentChild에게 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는 흐름만 이해해도 반은 성공이에요! 계속해서 함께 배워봐요! 🚀

답글 남기기