
안녕하세요! 오늘은 리액트의 단방향 데이터 흐름(One-way Data Flow)에 대해 설명하는 글을 작성해 보려고 합니다!
리액트의 매력?이라고 할 수도 있고, 리액트를 어렵게 하는 요소라고도 할 수 있는ㅎㅎ 단방향 데이터 흐름의 개념을 제대로 이해하면 컴포넌트 간 데이터 전달과 상태 관리가 어떻게 되는지 예측할 수 있기 때문에 알아두는 것이 좋겠죠!
그럼 지금부터 하나씩 살펴보도록 하겠습니다!
🔸 리액트의 단방향 데이터 흐름이란?
리액트에서는 데이터가 한 방향으로만 흐릅니다!
즉, 부모 컴포넌트에서 자식 컴포넌트로만 데이터를 전달할 수 있고, 반대 방향(자식에서 부모로 직접 데이터 전달)으로의 데이터 전달은 불가능합니다.
자식 컴포넌트가 부모 컴포넌트에 영향을 주고 싶다면 콜백 함수를 props로 전달하여 부모의 상태를 변경하는 방식을 사용해야 하죠.
🔸 단방향 데이터 흐름의 동작 방식
📌부모 → 자식 데이터 전달
리액트 컴포넌트의 상태(state)가 변경되면 부모 컴포넌트에서 그 상태를 자식 컴포넌트에 props로 전달해 줍니다.
자식 컴포넌트는 전달받은 데이터를 그대로 사용하거나, 렌더링에 반영하게 되죠.
코드 예시를 통해 좀 더 자세히 알아볼게요!
import React, { useState } from 'react';
function ChildComponent({ message }) {
return <p>자식 컴포넌트의 메시지: {message}</p>;
}
function ParentComponent() {
const [message, setMessage] = useState('안녕하세요, 리액트!');
return (
<div>
<h2>부모 컴포넌트</h2>
<ChildComponent message={message} />
<button onClick={() => setMessage('리액트의 단방향 데이터 흐름!')}>
메시지 변경하기
</button>
</div>
);
}
export default ParentComponent;
위 코드에서는 ParentComponent가 상태 message를 가지고 있고, 이를 ChildComponent에 props로 전달합니다.
버튼을 클릭하면 부모의 상태가 변경되고, 이에 따라 자식 컴포넌트도 새로운 메시지를 보여주게 됩니다.
위 코드로 데이터의 흐름은 부모 → 자식으로 단방향으로 흐르는 것을 볼 수 있습니다.
📌자식 → 부모 데이터 전달 (콜백 함수 활용)
자식이 부모의 데이터를 직접 변경할 수는 없지만 콜백 함수를 props로 전달하면 가능합니다!!
import React, { useState } from 'react';
function ChildComponent({ onUpdate }) {
return (
<div>
<p>자식 컴포넌트입니다.</p>
<button onClick={() => onUpdate('자식이 보낸 데이터!')}>
부모에게 데이터 전달
</button>
</div>
);
}
function ParentComponent() {
const [message, setMessage] = useState('아직 데이터가 없습니다.');
// updateMessage 함수를 정의하여 부모의 상태를 변경합니다.
const updateMessage = (childData) => {
setMessage(childData);
};
return (
<div>
<h2>부모 컴포넌트</h2>
<p>부모 상태: {message}</p>
{/* updateMessage 함수를 onUpdate라는 이름으로 자식에게 전달합니다. */}
<ChildComponent onUpdate={updateMessage} />
</div>
);
}
export default ParentComponent;
- 부모 컴포넌트에서는 updateMessage 함수를 정의하여 자식 컴포넌트에서 전달받은 데이터를 기반으로 상태를 변경합니다.
- 이 함수는 onUpdate라는 prop으로 자식 컴포넌트에 전달됩니다.
- 자식 컴포넌트에서는 버튼 클릭 시 onUpdate를 호출하여 부모의 message 상태를 업데이트합니다.
위 코드처럼 자식이 부모의 데이터를 변경하고 싶을 때는 부모에게 변경 요청을 하는 방식을 사용합니다.
🔸 단방향 데이터 흐름의 장점
그렇다면 리액트는 왜 단방향 데이터 흐름을 사용할까요?
✅ 예측 가능성
- 데이터가 오직 한 방향(부모 → 자식)으로만 흐르기 때문에 상태 변화를 예측하기 쉬움.
- 특정 이벤트가 발생했을 때 어떤 데이터가 변경될지 좀 더 명확하게 알 수 있음.
✅ 디버깅 용이
- 데이터가 여러 방향으로 흘러가면, 버그가 발생했을 때 원인을 찾기 어려움.
- 단방향 데이터 흐름을 사용하면 어떤 컴포넌트가 데이터를 변경했는지 추적하기 쉬워 디버깅이 간편해짐.
✅ 컴포넌트 간의 역할 분리
- 부모는 데이터를 소유하고, 자식은 데이터를 보여주는 역할만 담당하게 됨.
- 이는 UI와 로직의 분리를 도와주어, 각 컴포넌트가 맡은 역할에 충실할 수 있도록 함.
🔸 단방향 데이터 흐름의 단점
단방향 데이터 흐름은 예측 가능성과 유지보수성 등의 장점이 있지만 단점도 있겠죠?
특히 규모가 큰 애플리케이션에서는 몇 가지 단점이 두드러질 수 있는데 살펴보시죠!
✅ Props Drilling (깊은 컴포넌트 트리에서 발생하는 문제)
- 부모에서 자식 → 손자 → 증손자 컴포넌트로 데이터를 전달해야 할 때 중간 컴포넌트들이 불필요하게 props를 받아 전달만 하는 역할을 하게 됨.
- 트리가 깊어질수록 코드가 복잡해지고 유지보수가 어려워짐.
👉 해결 방법: Context API, Redux, Recoil 같은 전역 상태 관리 도구를 활용하여 중간 단계를 생략할 수 있음.
✅ 상태가 부모 컴포넌트에 집중됨
- 모든 상태를 부모 컴포넌트가 관리해야 하므로, 부모의 코드가 지나치게 복잡해질 수 있음.
- 여러 상태를 관리하다 보면 부모 컴포넌트의 역할이 많아지고, 로직이 분산되기 어려움.
👉 해결 방법: 적절히 상태를 분리하여 하위 컴포넌트에서도 관리할 수 있도록 설계하거나, Context API를 활용하여 전역적으로 관리 가능.
✅ 자식이 부모 상태를 변경하려면 콜백 함수를 사용해야 함
- 자식이 부모의 데이터를 직접 변경할 수 없기 때문에, 부모에서 콜백 함수를 생성하여 props로 넘겨야 함.
- 이 방식은 코드가 길어지고 복잡해질 수 있으며, 특히 많은 상태를 다루는 경우 여러 개의 콜백 함수를 관리해야 하는 부담이 생김.
👉 해결 방법: 전역 상태 관리 라이브러리(Redux, Zustand 등)를 활용하면 부모-자식 간 props 전달 없이 상태를 변경 가능.
🔸 마무리
- 데이터 흐름
- 부모 → 자식: 상태를 부모가 소유하고, 자식은 props로 전달받아 렌더링함.
- 자식 → 부모: 콜백 함수를 통해 간접적으로 부모의 상태를 변경함.
- 장점
- 예측 가능성: 데이터 흐름이 한 방향이므로 상태 변경 원인을 쉽게 파악할 수 있음.
- 디버깅 용이: 데이터 변경 지점을 명확히 알 수 있어 버그 추적이 쉬움.
- 역할 분리: 부모는 데이터 관리, 자식은 표현에 집중하여 책임이 분리됨.
- 단점
- Props Drilling: 깊은 컴포넌트 트리에서는 불필요하게 여러 단계에 props를 전달해야 함.
- 상태 집중: 모든 상태가 부모에 몰리면 코드가 복잡해짐.
- 콜백 복잡성: 자식에서 부모 상태 변경 시 여러 콜백 함수 관리 필요.
- 단점 해결 방안
- 전역 상태 관리 도구: Context API, Redux, Recoil 등을 활용해 Props Drilling과 상태 집중 문제를 완화.
- 독립적 컴포넌트 설계: 각 컴포넌트가 필요한 상태를 자체적으로 관리하도록 분리.
'🖥️개발 > 🐋React' 카테고리의 다른 글
[Zustand] Zustand란? 리액트에서 Zustand를 사용하는 이유 (0) | 2025.02.23 |
---|---|
[React] ref란? (0) | 2025.02.16 |
[React] <input>과 <label>은 함께 써요! with. React.useId Hook (0) | 2025.01.26 |
[React] 엄격 모드(StrictMode)를 사용하는 이유 with 순수 함수 (0) | 2025.01.19 |
React.createElement의 매개변수 (0) | 2025.01.12 |