React Context를 사용한 중첩 컴포넌트 트리에서 불필요한 재렌더링 수정
Source: Dev.to

모든 React 성능 문제가 오류로 나타나는 것은 아닙니다.
일부는 개발 중에 조용히 나타나며, 간단한 UI 상호작용이 예상보다 무겁게 느껴질 때가 있습니다.
이 글에서는 prop drilling과 부적절한 상태 배치 때문에 발생한 실제 개발 시 문제와, 상태 구조를 재조정하여 불필요한 재렌더링, API 호출, 무거운 UI 업데이트를 어떻게 해결했는지 살펴봅니다.
앱은 React를 사용하고 Highcharts 기반 시각화를 렌더링합니다(재렌더링 비용이 높음). 컴포넌트 트리 깊숙이(2~3단계 아래) 버튼이 있는 자식 컴포넌트가 있었습니다.
요구 사항
버튼을 클릭하면 모달을 표시합니다. 종이에 쓰기엔 간단합니다.
초기 구현
모달 상태를 부모 컴포넌트에 정의했습니다.
const Parent = () => {
const [isModalOpen, setIsModalOpen] = useState(false);
useEffect(() => {
fetchData();
}, []);
return ;
};
setIsModalOpen을 여러 레벨을 거쳐 props 로 전달해 버튼에 도달했습니다.
setIsModalOpen(true)}>
Open modal
기능적으로는 동작했지만, 아키텍처적으로는 문제가 있었습니다.
테스트 중 관찰된 점
개발 중에 기능을 가볍게 테스트하면서 다음을 발견했습니다.
- 버튼 클릭 시 눈에 보이는 UI 일시정지
- Highcharts 재렌더링
- API 호출이 다시 트리거됨
각 클릭마다 부모 상태가 업데이트되어 다음을 초래했습니다.
- 부모 컴포넌트 재렌더링
- 부모에 연결된 부수 효과가 다시 실행
- 비용이 많이 드는 UI가 불필요하게 재초기화
아무것도 깨지지는 않았지만 비용은 실제였습니다.
근본 원인
문제는 상태 배치에 있었습니다.
- 모달 상태는 UI 전용이었습니다.
- 데이터 페칭과 무거운 렌더링을 담당하는 부모 컴포넌트에 존재했습니다.
- Prop drilling 때문에 로컬 상호작용이 전역 부수 효과와 강하게 결합되었습니다.
React 애플리케이션이 성장하면서 흔히 발생하는 아키텍처 누수입니다.
해결책: Context 로 UI 상태 격리
모달 상태를 부모에서 완전히 제거하고, 모달 가시성을 위한 전용 Context 를 도입합니다.
import { createContext, useState } from "react";
const ModalContext = createContext(null);
export const ModalProvider = ({ children }) => {
const [isOpen, setIsOpen] = useState(false);
return (
<ModalContext.Provider value={{ isOpen, setIsOpen }}>
{children}
</ModalContext.Provider>
);
};
모달 상태가 의미 있는 최상위 경계에 Provider 를 배치합니다. 모달을 열거나 닫아야 하는 컴포넌트는 직접 Context 를 사용합니다.
import { useContext } from "react";
const { setIsOpen } = useContext(ModalContext);
이제 Prop drilling도 없고, 부모 컴포넌트와도 얽히지 않습니다.
결과
이 변경 후:
- 모달을 열 때 부모 컴포넌트가 더 이상 재렌더링되지 않음.
- API 호출이 명시적으로 필요할 때만 실행됨.
- Highcharts 가 안정적으로 유지됨.
- UI 상호작용이 즉각적이고 예측 가능해짐.
사용자에게 보이는 동작은 동일했지만, 아키텍처는 더 깔끔하고 성능도 향상되었습니다.
주요 시사점
- Prop drilling 은 코드가 올바르더라도 성능 문제를 숨길 수 있습니다.
- UI 전용 상태는 데이터 페칭 로직과 함께 두어서는 안 됩니다.
- 버튼 클릭이 무관한 부수 효과를 일으킨다면, 상태 경계가 잘못된 것입니다.
- Context API 는 전역 데이터를 위한 것뿐만 아니라 UI 관심사를 격리하는 데도 효과적입니다.
React에서 성능 문제는 종종 위장된 설계 문제입니다.