Redux 스타일 셀렉터로 React Context 재렌더링 방지

발행: (2025년 12월 7일 오후 11:48 GMT+9)
6 min read
원문: Dev.to

Source: Dev.to

문제

React Context를 사용할 때, 해당 컨텍스트를 구독하는 모든 컴포넌트는 그 컨텍스트 안의 어떤 값이든 변경될 때마다 다시 렌더링됩니다.

import { createContext, useState } from 'react';

const AppContext = createContext();

function AppProvider({ children }) {
  const [user, setUser] = useState(null);
  const [theme, setTheme] = useState('light');
  const [notifications, setNotifications] = useState([]);

  return (
    {children}
  );
}
import { useContext } from 'react';

function UserProfile() {
  const { user } = useContext(AppContext);
  return Hello, {user?.name}!;
}

문제: UserProfileuser만 필요함에도 불구하고 theme이나 notifications가 바뀔 때마다 다시 렌더링됩니다.

해결책

use-context-hook은 Redux‑style 셀렉터를 사용해 필요한 값만 구독하도록 해줍니다.

import { createContextHook, useContextHook } from 'use-context-hook';
import { useState } from 'react';

// 컨텍스트 생성
const AppContext = createContextHook();

// Provider는 그대로 유지
function AppProvider({ children }) {
  const [user, setUser] = useState(null);
  const [theme, setTheme] = useState('light');
  const [notifications, setNotifications] = useState([]);

  return (
    {children}
  );
}

// 컴포넌트는 `user`가 바뀔 때만 다시 렌더링
function UserProfile() {
  const user = useContextHook(AppContext, 'user');
  return Hello, {user?.name}!;
}

이제 UserProfile오직 user가 바뀔 때만 업데이트됩니다.

네 가지 유연한 셀렉터 패턴

1. 문자열 셀렉터 (단일 값)

const user = useContextHook(AppContext, 'user');

2. 배열 셀렉터 (다중 값)

const { user, theme } = useContextHook(AppContext, ['user', 'theme']);

3. 객체 셀렉터 (명시적 선택)

const { user, theme } = useContextHook(AppContext, {
  user: 1,
  theme: 1,
});

4. 함수 셀렉터 (Redux‑Style)

// 특정 필드만 선택
const { user, theme } = useContextHook(AppContext, (state) => ({
  user: state.user,
  theme: state.theme,
}));

// 혹은 값을 파생시킴
const userName = useContextHook(AppContext, (state) => state.user?.name);

실제 성능 영향

  • 전: 사용자 인터랙션당 50번 이상의 불필요한 재렌더링
  • 후: 실제로 업데이트가 필요한 2~3개의 컴포넌트만 렌더링

예시: 사용자가 입력 필드에 타이핑할 때 폼의 재렌더링 횟수가 47에서 3으로 감소했습니다.

작동 원리 (기술적인 부분)

  • useContextHook은 제공된 셀렉터를 기반으로 컴포넌트에 리스너를 등록합니다.
  • 컨텍스트 값이 변하면 라이브러리는 이전 값과 새로운 값 모두에 셀렉터를 실행합니다.
  • 셀렉터 결과를 깊은 비교(deep comparison)합니다.
  • 선택된 값이 변경된 경우에만 재렌더링을 트리거합니다.

이 방식은 중첩된 객체가 있더라도 변경되지 않은 데이터에 대한 재렌더링을 방지합니다.

TypeScript 지원

interface AppContextType {
  user: User | null;
  theme: 'light' | 'dark';
  notifications: Notification[];
}

const AppContext = createContextHook();

// User | null 로 추론됨
const user = useContextHook(AppContext, 'user');

// { user: User | null; theme: 'light' | 'dark' } 로 추론됨
const { user, theme } = useContextHook(AppContext, ['user', 'theme']);

완전한 타입 추론과 안전성을 기본 제공합니다.

언제 사용해야 할까?

사용 사례

  • 값이 많은 대형 컨텍스트 객체
  • 컴포넌트가 컨텍스트의 특정 부분만 필요로 할 때
  • 기본 Context API 사용 시 성능 문제가 발생할 때
  • Redux 없이 Redux‑like 셀렉터 패턴을 원할 때

사용하지 말아야 할 경우

  • 컨텍스트에 1~2개의 값만 있을 때
  • 모든 컴포넌트가 전체 컨텍스트를 필요로 할 때
  • 이미 Redux, Zustand 등 선택적 구독을 지원하는 상태 관리 라이브러리를 사용 중일 때

설치

npm install use-context-hook
# or
yarn add use-context-hook
# or
pnpm add use-context-hook

실시간 예시

  • 문자열 셀렉터:
  • 배열 셀렉터:
  • 객체 셀렉터:
  • Redux‑Style 함수 셀렉터:

대안과 비교

라이브러리번들 크기셀렉터 패턴TypeScript재렌더링 방지
use-context-hook~2 KB4가지 패턴전체 지원
use-context-selector~3 KB함수만부분 지원
React Context (내장)0 KB없음내장아니오
Redux~15 KB+지원지원예 (하지만 무겁다)

마무리

React Context는 강력하지만 기본 동작은 큰 앱에서 불필요한 재렌더링을 초래할 수 있습니다. use-context-hook은 다음을 제공합니다:

  • 작음 – 최소화된 ~2 KB
  • 빠름 – 선택된 값에만 깊은 비교 수행
  • 타입 안전 – 완전한 TypeScript 지원
  • 유연함 – 네 가지 셀렉터 패턴
  • 의존성 제로 – React만 피어 의존성으로 사용

Redux‑style 선택적 구독을 복잡성 없이 구현하고 싶다면 활용해 보세요.

링크

  • npm 패키지:
  • GitHub 저장소:
  • 전체 문서:
Back to Blog

관련 글

더 보기 »