서론
React 프로젝트에서 컴포넌트 간 상태를 공유하고 관리하는 일은 자주 발생합니다. 그러나 여러 컴포넌트가 공통된 상태를 사용해야 할 때, props drilling이라는 문제가 발생하곤 합니다.
props drilling이란 상태나 함수를 필요한 컴포넌트로 전달하기 위해 여러 중간 컴포넌트를 거쳐야 하는 상황을 말합니다. 이는 코드의 복잡도를 증가시키고 유지보수성을 떨어뜨립니다.
React의 Context API는 이러한 문제를 해결하고 성능까지 개선할 수 있는 강력한 도구입니다. 이번 포스팅에서는 props drilling이 있는 상황과 Context로 이를 해결하여 성능을 개선하는 방법을 살펴보겠습니다.
문제상황
1. Props Drilling의 문제
props drilling이 있는 상황을 살펴보겠습니다. 예를 들어, 사이드바 상태(isSidebarOpen)와 상태 변경 함수(toggleSidebar)를 전달해야 한다고 가정해보겠습니다.
Props Drilling 예제 코드
// App.js
import React, { useState } from 'react';
import Layout from './components/Layout';
const App = () => {
const [isSidebarOpen, setIsSidebarOpen] = useState(false);
const toggleSidebar = () => {
setIsSidebarOpen((prev) => !prev);
};
return (
<Layout isSidebarOpen={isSidebarOpen} toggleSidebar={toggleSidebar} />
);
};
export default App;
// Layout.js
import React from 'react';
import Navbar from './Navbar';
import HamburgerBtn from './HamburgerBtn';
const Layout = ({ isSidebarOpen, toggleSidebar }) => {
return (
<div className="layout-container">
<Navbar isSidebarOpen={isSidebarOpen} />
<HamburgerBtn isSidebarOpen={isSidebarOpen} toggleSidebar={toggleSidebar} />
</div>
);
};
export default Layout;
// HamburgerBtn.js
import React from 'react';
const HamburgerBtn = ({ isSidebarOpen, toggleSidebar }) => {
return (
<button
className={`hamburger-button ${isSidebarOpen ? 'shifted' : ''}`}
onClick={toggleSidebar}
>
☰
</button>
);
};
export default HamburgerBtn;
Props Drilling의 문제점 -> 연결다리가 생김에 따라 코드가 복잡해짐
App -> Layout -> HamburgetBtn
햄버거버튼을 클릭하면 사이드바의 상태가 변화해야하기에 기능을 추가하는 건 좋으나 이 화살표가 많아지면, props를 추가해주는 곳이 너 무 많아지기에 코드의 가독성도 어려워지며 유지 보수도 어려워진다.
1. 중간 컴포넌트의 역할 증가
• Layout은 단순히 Navbar와 HamburgerBtn을 렌더링하지만, isSidebarOpen과 toggleSidebar를 전달하는 추가 역할을 합니다. 이로 인해 코드가 복잡해집니다.
2. 컴포넌트 간 결합도 증가
• isSidebarOpen이나 toggleSidebar를 필요로 하지 않는 컴포넌트(Layout)도 props를 받아야 하므로 컴포넌트 간 결합도가 높아집니다.
3. 유지보수 어려움
• 상태나 함수가 더 깊은 계층의 컴포넌트에서 필요해지면, 모든 중간 컴포넌트에 props를 추가해야 합니다.
Context로 Props Drilling 해결하기
이제 Context를 사용해 props drilling 문제를 해결하고, 코드의 복잡도를 줄이겠습니다.
Context 적용 후 구조
1. SidebarContext: 글로벌 상태와 상태 변경 함수 정의.
2. SidebarProvider: 상태를 전역적으로 제공.
3. HamburgerBtn: useContext로 상태와 함수를 직접 가져옴
Context 적용 코드
1) SidebarContext 생성
// src/context/SidebarContext.jsx
import React, { createContext, useState } from 'react';
export const SidebarContext = createContext();
export const SidebarProvider = ({ children }) => {
const [isSidebarOpen, setIsSidebarOpen] = useState(false);
const toggleSidebar = () => {
setIsSidebarOpen((prev) => !prev);
};
return (
<SidebarContext.Provider value={{ isSidebarOpen, toggleSidebar }}>
{children}
</SidebarContext.Provider>
);
};
2) Context Provider 적용
App.js에서 SidebarProvider로 전체 컴포넌트를 감쌉니다
// App.js
import React from 'react';
import { SidebarProvider } from './context/SidebarContext';
import Layout from './components/Layout';
const App = () => (
<SidebarProvider>
<Layout />
</SidebarProvider>
);
export default App;
3) Context 사용
HamburgerBtn에서 useContext를 사용해 글로벌 상태를 가져옵니다.
// src/components/HamburgerBtn.jsx
import React, { useContext } from 'react';
import { SidebarContext } from '../context/SidebarContext';
const HamburgerBtn = () => {
const { isSidebarOpen, toggleSidebar } = useContext(SidebarContext);
return (
<button
className={`hamburger-button ${isSidebarOpen ? 'shifted' : ''}`}
onClick={toggleSidebar}
>
☰
</button>
);
};
export default HamburgerBtn;
성능 개선 포인트
1. props drilling 제거
• 상태와 함수를 중간 컴포넌트로 전달할 필요가 없어, 코드가 간결해지고 컴포넌트 간 결합도가 낮아집니다.
2. 불필요한 렌더링 방지
• Context를 구독하지 않는 컴포넌트는 리렌더링되지 않습니다.
3. 유지보수 용이성
• 상태 관리 로직이 Context로 중앙화되므로, 로직 변경이나 확장이 용이합니다.
최종 코드 구조
src/
|-- context/
| |-- SidebarContext.jsx
|
|-- components/
| |-- Layout.jsx
| |-- HamburgerBtn.jsx
| |-- Navbar.jsx
|
|-- App.js
결론
React Context는 props drilling 문제를 해결하는, State 그리고 함수를 중앙화 시켜서 성능 개선을 하는 방식입니다.
전역 상태 관리와 상태 변경 함수의 공유를 통해 코드의 간결함과 재사용성을 높일 수 있습니다.
'FrontEnd Develop' 카테고리의 다른 글
⏿실제 백엔드와 프론트엔드 통신 #1. 인증과 권한부여 <토큰> (0) | 2025.01.24 |
---|---|
Data Fetching : User의 능동성 여부와 useEffect의 올바른 공존 (0) | 2025.01.22 |
🚀 프론트엔드 성능 개선 가이드 #1. React DevTools 컴포넌트 & 프로파일러 기능 활용 (1) | 2025.01.15 |
<React + Vue.js> 프로젝트 내 로그인 기능 구현 가이드 With Dummy Server (0) | 2025.01.12 |
프론트엔드 개발을 위한 더미 서버 구축 <JSON Server Usage> (0) | 2025.01.11 |