Frontend

[React] useContext 사용해보기

min_ee 2025. 6. 26. 18:21

useContext란?

useContext는 컴포넌트가 가장 가까운 MyContext.Provider에서 제공하는 context 값을 읽게해주는 Hook이다.

값을 읽기만 하며, context 값을 설정하려면 Provider를 사용해야 한다.

const value = useContext(MyContext);

MyContext는 createContext()로 만든 객체이다.

useContext()는 현재 컴포넌트가 어떤 Provider 안에 위치해 있을 때만 동작한다.

하위 컴포넌트 어디에서든 값을 꺼내 쓸 수 있다는 점이 핵심이다.

 

왜 사용할까..?

React에서 props로 상태를 전달할 때 종종 이런 구조가 생긴다.

<App>
  <Layout>
    <Header>
      <ThemeToggler />
    </Header>
  </Layout>
</App>

이 구조에서 <ThemeToggler /> 까지 상태를 전달하려면

App 에서 ThemeToggler로 props를 계속 넘겨야 한다.

이걸 props drilling이라고 하는데, 코드가 복잡해지는 주 요인 중 하나이다.

 

해당 요인을 해결하기 위해 사용하는 것이 useContext이다.

 

실습해보기

테마 전환기

많이들 사용하는 다크모드로의 전환을 위한 테마 전환기로 실습을 해보았다.

ThemeContext.tsx

// ThemeContext.tsx
import { createContext, useContext, useState, type ReactNode } from "react";

type Theme = "light" | "dark";

interface ThemeContextType {
	theme: Theme;
	toggleTheme: () => void;
}

const ThemeContext = createContext<ThemeContextType | undefined>(undefined);

export const ThemeProvider = ({ children }: { children: ReactNode }) => {
	const [theme, setTheme] = useState<Theme>("light");

	const toggleTheme = () => {
		setTheme((prev) => (prev === "light" ? "dark" : "light"));
	};

	return (
		<ThemeContext.Provider value={{ theme, toggleTheme }}>
			{children}
		</ThemeContext.Provider>
	);
};

export const useTheme = () => {
	const context = useContext(ThemeContext);
	if (!context) throw new Error("useTheme must be used within a ThemeProvider");
	return context;
};

useTheme()훅에서 context가 undefined일 경우 예외를 던지게 함으로써, ThemeProvider로 감싸지않고 사용할 경우 바로 알 수 있도록 했다.

 

ThemeToggler.tsx

import { useTheme } from "../../context/ThemeContext";

const ThemeToggler = () => {
	const { theme, toggleTheme } = useTheme();

	return (
		<button className="p-6" onClick={toggleTheme}>
			current theme: {theme}
		</button>
	);
};

export default ThemeToggler;

ThemeBox.tsx

import { useTheme } from "../../context/ThemeContext";

const ThemedBox = () => {
	const { theme } = useTheme();

	return (
		<div
			style={{
				padding: "1rem",
				textAlign: "center",
				marginTop: "1rem",
				backgroundColor: theme === "light" ? "white" : "black",
				color: theme === "light" ? "black" : "white",
			}}
		>
			테마가 적용된 박스입니다.
		</div>
	);
};

export default ThemedBox;

 

UseContextPage.tsx

import ThemeToggler from "../components/UseContext/ThemeToggler";
import ThemedBox from "../components/UseContext/ThemedBox";
import { ThemeProvider } from "../context/ThemeContext";

const UseContextPage = () => {
	return (
		<ThemeProvider>
			<div>
				<h1>useContext</h1>
				<ThemeToggler />
				<ThemedBox />
			</div>
		</ThemeProvider>
	);
};

export default UseContextPage;

해당 실습에서는 UseContextPage에 적용을 해두었지만

보통은 앱 전역에서 사용되므로 App.tsx에 적용한다.

 

실행 결과화면

current theme 버튼을 누르면 다크/라이트모드가 전환이 되는 것을 확인할 수 있다.

props 없이도 전역 상태를 여러 컴포넌트에서도 공유할 수 있음을 확인할 수 있다.

 

createContext(undefined)를 사용한 이유

createContext<ThemeContextType | undefined>(undefined) 에 undefined를 왜 써야할까? 라는 궁금증이 생겨 찾아보게되었다.

- Provider 없이 useContext()를 호출해도 오류가 나지 않는다

  -> 기본 값이 있으면 오류 없이 작동하지만, 의도한 동작이 아닐 수 있기 때문에!

- 명확하게 에러를 던지기 위함

  -> useTheme()내부에 context가 undefined일 경우 명확하게 예외를 발생시켜 실수를 빨리 잡을 수 있다.

 

정리

- useContext는 props 없이 전역 상태를 쉽게 공유할 수 있는 Hook이다.

- createContext()와 커스텀 훅으로 사용 범위를 명확하게 제한할 수 있다.

- 테마, 로그인 정보, 언어 설정 등 앱 전역에 영향을 주는 상태에 적합하다.

- props drilling 없이 컴포넌트 간 데이터 공유가 가능하다.

 

 

전역 상태 관리에 zustand를 주로 사용하고 있었는데

useContext가 어떤 문제를 해결하기 위해 만들어 졌는지 직접 써보며 이해할 수 있었다.

 

직접 createContext부터 Provider구성, 커스텀 훅 만들기가지 해보니 zustand같은 상태 관리 도구들이 왜 등장했는지도 알 것 같았다.

 

복잡한 앱에서는 한계가 있을 수 있겠지만 작은 프로젝트나 간단한 전역 설정에는 여전히 유용한 도구라는 걸 위 글을 작성하며 알게 되었다.

 

공식 문서

 

useContext – React

The library for web and native user interfaces

react.dev