icon안동민 개발노트

useContext 훅으로 데이터 공유하기


 React의 Context API와 useContext 훅은 컴포넌트 트리 전체에 걸쳐 데이터를 효과적으로 공유할 수 있게 해주는 강력한 도구입니다.

 이를 통해 props drilling 문제를 해결하고 전역 상태를 관리할 수 있습니다.

Context API의 개념

 Context는 React 컴포넌트 트리 안에서 전역적으로 데이터를 공유할 수 있는 방법을 제공합니다.

 이는 사용자 인증 정보, 테마, 언어 설정 등과 같이 애플리케이션의 여러 부분에서 필요한 데이터를 관리하는 데 유용합니다.

Context 생성 및 Provider 설정

 Context를 생성하고 Provider를 설정하는 방법은 다음과 같습니다.

import React, { createContext, useState } from 'react';
 
// Context 생성
export const ThemeContext = createContext();
 
// Provider 컴포넌트
export function ThemeProvider({ children }) {
  const [theme, setTheme] = useState('light');
 
  const toggleTheme = () => {
    setTheme(prevTheme => prevTheme === 'light' ? 'dark' : 'light');
  };
 
  return (
    <ThemeContext.Provider value={{ theme, toggleTheme }}>
      {children}
    </ThemeContext.Provider>
  );
}

 이 예제에서는 테마 관련 상태와 함수를 포함하는 Context를 생성하고, Provider 컴포넌트를 통해 하위 컴포넌트에 이 Context를 제공합니다.

useContext 훅 사용하기

 useContext 훅을 사용하여 Consumer 컴포넌트에서 Context 값을 쉽게 사용할 수 있습니다.

import React, { useContext } from 'react';
import { ThemeContext } from './ThemeProvider';
 
function ThemedButton() {
  const { theme, toggleTheme } = useContext(ThemeContext);
 
  return (
    <button 
      onClick={toggleTheme}
      style={{ 
        background: theme === 'light' ? '#fff' : '#333',
        color: theme === 'light' ? '#333' : '#fff'
      }}
    >
      Toggle Theme
    </button>
  );
}

 이 컴포넌트는 ThemeContext에서 제공하는 theme 값과 toggleTheme 함수를 사용하여 테마를 변경할 수 있는 버튼을 렌더링합니다.

여러 Context 조합하기

 여러 개의 Context를 사용해야 할 때는 다음과 같이 중첩하여 사용할 수 있습니다.

import { ThemeProvider } from './ThemeContext';
import { UserProvider } from './UserContext';
 
function App() {
  return (
    <ThemeProvider>
      <UserProvider>
        <MainContent />
      </UserProvider>
    </ThemeProvider>
  );
}

 그리고 Consumer 컴포넌트에서는 필요한 Context를 각각 useContext로 가져와 사용할 수 있습니다.

import React, { useContext } from 'react';
import { ThemeContext } from './ThemeContext';
import { UserContext } from './UserContext';
 
function UserProfile() {
  const { theme } = useContext(ThemeContext);
  const { user } = useContext(UserContext);
 
  return (
    <div style={{ background: theme === 'light' ? '#fff' : '#333' }}>
      <h2>{user.name}</h2>
      <p>{user.email}</p>
    </div>
  );
}

Context 사용 시 성능 고려사항

 Context를 사용할 때는 다음과 같은 성능 관련 사항을 고려해야 합니다.

 1. 불필요한 리렌더링

 Context 값이 변경되면 해당 Context를 사용하는 모든 컴포넌트가 리렌더링됩니다.

 따라서 자주 변경되는 값과 그렇지 않은 값을 분리하여 관리하는 것이 좋습니다.

const FastChangeContext = createContext();
const SlowChangeContext = createContext();
 
function Provider({ children }) {
  const [fastChangingValue, setFastChangingValue] = useState(0);
  const [slowChangingValue, setSlowChangingValue] = useState(0);
 
  return (
    <SlowChangeContext.Provider value={slowChangingValue}>
      <FastChangeContext.Provider value={fastChangingValue}>
        {children}
      </FastChangeContext.Provider>
    </SlowChangeContext.Provider>
  );
}

 2. 메모이제이션 활용

 React.memo, useMemo, useCallback 등을 사용하여 불필요한 리렌더링을 방지할 수 있습니다.

const MemoizedChild = React.memo(function Child({ text }) {
  const theme = useContext(ThemeContext);
  return <div style={{ color: theme.color }}>{text}</div>;
});

Context 사용 시 주의점

  1. 남용 주의 : 모든 전역 상태를 Context로 관리하려고 하면 애플리케이션의 구조가 복잡해질 수 있습니다. 정말 필요한 경우에만 Context를 사용하세요.
  2. 기본값 설정 : createContext에 기본값을 제공하면, Provider 없이 Context를 사용할 때 발생할 수 있는 오류를 방지할 수 있습니다.
const ThemeContext = createContext({ theme: 'light', toggleTheme: () => {} });
  1. 동적 Context 생성 주의 : 렌더링 중에 새로운 Context 객체를 생성하지 마세요. 이는 의도치 않은 리렌더링을 유발할 수 있습니다.
  2. Provider 최적화 : Provider의 value prop에 객체를 직접 전달하면 불필요한 리렌더링이 발생할 수 있습니다. 대신 상태를 분리하거나 useMemo를 사용하세요.
function ThemeProvider({ children }) {
  const [theme, setTheme] = useState('light');
 
  const contextValue = useMemo(() => ({
    theme,
    toggleTheme: () => setTheme(t => t === 'light' ? 'dark' : 'light')
  }), [theme]);
 
  return (
    <ThemeContext.Provider value={contextValue}>
      {children}
    </ThemeContext.Provider>
  );
}

 Context API와 useContext 훅은 React 애플리케이션에서 전역 상태를 관리하고 컴포넌트 간 데이터 공유를 용이하게 하는 강력한 도구입니다.

 이를 통해 props drilling 문제를 해결하고 애플리케이션의 구조를 더 깔끔하게 유지할 수 있습니다.

 그러나 Context를 사용할 때는 성능 영향을 고려해야 하며, 불필요한 리렌더링을 방지하기 위해 적절한 최적화 기법을 적용해야 합니다.

 또한, Context의 남용은 애플리케이션의 구조를 복잡하게 만들 수 있으므로, 전역적으로 공유해야 하는 데이터에 대해서만 Context를 사용하는 것이 좋습니다.

 적절히 사용된 Context는 React 애플리케이션의 상태 관리를 크게 개선할 수 있으며, 특히 중간 규모 이상의 프로젝트에서 그 가치를 발휘합니다.

 더 복잡한 상태 관리가 필요한 경우 Redux나 MobX 같은 전용 상태 관리 라이브러리를 고려할 수 있지만, 많은 경우 Context API만으로도 충분한 솔루션을 제공할 수 있습니다.