React에서 데이터 흐름을 설계할 때 흔히 마주치는 두 가지 방식이 있습니다:
각 방식은 상황에 따라 장단점이 분명하게 나뉘며, 이를 잘 이해하고 선택하는 것이 중요합니다.
실제로 제가 진행했던 프로젝트에서도 해당 주제로 고민이 되었던 순간이 있었는데 정답은 없는 것 같습니다. 마지막에 얘기할 결론에 따라 적절하게 판단, 적용 하는 것이 중요하다고 생각합니다.
function App() {
const { data, isLoading } = useQuery(['posts'], fetchPosts);
return <PostList data={data} isLoading={isLoading} />;
}
function PostList({ data, isLoading }) {
if (isLoading) return <p>Loading...</p>;
return (
<ul>
{data.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
);
}
useQuery 같은 훅을 최상위 컴포넌트에서 실행하고 결과를 props로 넘깁니다.💡 중간 전달 컴포넌트가 많아질 경우 Context API와의 병용도 고려할 수 있습니다.
// store.ts
const postSlice = createSlice({
name: 'post',
initialState: { data: [], isLoading: false },
reducers: { setPosts: (state, action) => { state.data = action.payload; } },
});
export const { setPosts } = postSlice.actions;
export default postSlice.reducer;
// 컴포넌트 내부
function PostList() {
const dispatch = useDispatch();
const data = useSelector((state) => state.post.data);
useEffect(() => {
dispatch(fetchPostsAsync());
}, []);
return <ul>{data.map((post) => <li key={post.id}>{post.title}</li>)}</ul>;
}
useSelector로 접근합니다.⚠️ 과한 상태 공유는 오히려 유지보수를 어렵게 할 수 있으니, 필요한 경우에만 도입하는 것이 좋습니다.
| 상황 | 추천 방식 |
|---|---|
| 컴포넌트 구조가 얕고 명확한 경우 | props 기반 전달 |
| 여러 컴포넌트에서 동일한 데이터를 참조해야 하는 경우 | 전역 상태 관리 도입 |
| 빠른 시제품 또는 기능 단위 개발 | props + Context API |
| 대규모 프로젝트에서 상태 간 복잡한 관계가 있는 경우 | Redux, Zustand 등 |