React에서 useContext Hook은 컴포넌트 트리의 깊은 곳에 있는 컴포넌트에 데이터를 직접 전달할 수 있게 해 줍니다. React에서 context를 사용하면 단계마다 일일이 props를 넘겨주지 않고도 컴포넌트 트리 전체에 데이터를 제공할 수 있어 편리합니다.
Context - 컴포넌트 간 데이터 공유의 효율적인 방법
목차
위의 목차를 클릭하면 해당 글로 자동 이동 합니다.
1. Context란?
Context는 React 애플리케이션에서 전역 데이터를 관리하고 공유할 수 있는 방법입니다. 예를 들어, 사용자 인증 정보, 테마, 언어 설정 등 전역적으로 사용되어야 하는 데이터는 Context를 통해 쉽게 관리할 수 있습니다.
import {createContext} from 'react';
const Context = createContext();
createContext()를 사용해 Context 객체를 생성하면 필요한 곳에서 데이터를 사용할 수 있도록 제공합니다.
2. useContext 사용법
useContext는 특정 Context의 값을 가져올 때 사용하는 Hook입니다. useContext는 반드시 Provider와 함께 사용해야 합니다. Provider는 컴포넌트 트리에서 상위에 위치하며 하위 컴포넌트가 Context 값을 사용할 수 있도록 전달합니다.
import { createContext, useContext } from 'react';
const ColorContext = createContext('white');
function App() {
return (
<ColorContext.Provider value="black">
<Container />
</ColorContext.Provider>
);
}
function Container() {
return <Box />;
}
function Box() {
const bgColor = useContext(ColorContext);
return <div style={{ width: "300px", height: "300px", background: bgColor }}>{bgColor} Box</div>;
}
위 예시에서는 ColorContext를 생성하고, Provider를 통해 value로 black 테마를 모든 하위 컴포넌트에 전달합니다. useContext를 사용한 Box 컴포넌트는 ColorContext의 값(black)을 받아와 버튼의 background 스타일을 설정합니다.
3. useContext로 불필요한 Props 드릴링 제거
Props 드릴링이란?
React에서 상위 컴포넌트가 하위 컴포넌트로 데이터를 전달하는 과정을 Props 드릴링(props drilling)이라고 부릅니다. 이때 컴포넌트 구조가 복잡해지고 깊어질수록 , 관리하기가 어려워집니다. useContext를 사용하면 이러한 문제를 해결할 수 있습니다.
Props 드릴링 예시
import {useState} from 'react';
export default function App() {
const [name, setName] = useState('Kim');
return <Parent name={name} />;
}
function Parent({ name }) {
return <DepthOne name={name} />;
}
function DepthOne({ name }) {
return <DepthTwo name={name} />;
}
function DepthTwo({ name }) {
return <div>name: {name}</div>;
}
위 예시는 name을 DepthTwo 컴포넌트에 전달하기 위해 각 컴포넌트마다 props를 반복해서 사용하고 있습니다. 하지만 useContext를 사용하면 이 과정을 생략할 수 있습니다.
useContext 예시
import { createContext, useContext, useState } from 'react';
const NameContext = createContext();
export default function App() {
const [name, setName] = useState('Kim');
return (
<NameContext.Provider value={{ name, setName }}>
<Parent />
</NameContext.Provider>
);
}
function Parent() {
return <DepthOne />;
}
function DepthOne() {
return <DepthTwo />;
}
function DepthTwo() {
const { name, setName } = useContext(NameContext);
return <div>name: {name}</div>;
}
useContext를 사용하면 하위 컴포넌트에서 직접 name을 가져올 수 있으므로, 불필요한 props 전달 과정을 생략할 수 있습니다.
4. useContext로 글로벌 상태 관리
useContext는 작은 규모의 애플리케이션에서는 전역 상태를 관리하는 훌륭한 방법이 될 수 있습니다. 다만, 애플리케이션 규모가 커지면 상태 관리 라이브러리(Redux 등)를 사용하는 것이 더 나을 수 있습니다. 하지만, 간단한 전역 데이터 관리에는 useContext가 충분히 유용합니다.
import { createContext, useContext, useState } from 'react';
const ColorContext = createContext();
export default function App() {
return (
<ColorProvider defaultColor="black">
<ToggleButton />
</ColorProvider>
);
}
function ColorProvider({ defaultColor, children }) {
const [color, setColor] = useState(defaultColor);
const toggleColor = () => {
setColor((prevColor) => (prevColor === 'black' ? 'white' : 'black'));
};
return (
<ColorContext.Provider value={{ color, toggleColor }}>
{children}
</ColorContext.Provider>
);
}
function ToggleButton() {
const { color, toggleColor } = useContext(ColorContext);
return (
<div>
<div
style={{
width: '300px',
height: '300px',
backgroundColor: color,
}}
></div>
<button onClick={toggleColor}>Toggle Theme</button>
</div>
);
}
위 예시는 ColorProvider에서 전역으로 관리하는 color를 Togglebutton 컴포넌트에서 변경하는 예제입니다.
5. Context Api를 언제 사용할까?
리액트 공식문서에서는 context를 사용하면 컴포넌트를 재사용하기 어려워지므로 꼭 필요할 때만 쓸 것을 권장한다고 합니다.
Context Api를 사용하면 좋은 경우
- 전역적인 데이터의 사용이 필요한 경우 (언어 설정, 다크/라이트 모드, 로그인 상태)
- Props 드릴링을 방지하고 싶은 경우
Context Api를 사용을 피해야 하는 경우
- 로컬 상태 관리에 사용 (데이터가 해당 컴포넌트의 하위 컴포넌트나 특정 컴포넌트에서만 사용되는 경우)
- 컴포넌트 재사용이 필요한 경우 (Context를 사용하면 컴포넌트를 다른 환경에서 재사용하기 어려워짐)
- 단순히 데이터만 전달하는 경우 (텍스트나, 스타일 같은 작은 데이터는 props로 전달하는 것이 더 직관적이고 적합)
React의 Context API는 전역 상태 관리와 props drilling 문제를 해결하는 데 유용한 도구입니다. 하지만 너무 빈번하게 사용하거나 불필요한 경우에 사용하면 컴포넌트 재사용성과 유지보수성을 해칠 수 있으므로, 상황에 맞게 적절하게 사용해야 합니다. Context를 사용할 때 아래 질문들을 고려하면 좋을 것 같습니다.
- 이 데이터가 여러 컴포넌트에서 필요하고 전역적으로 공유되어야 하는가?
- 이 데이터가 특정 깊이의 하위 컴포넌트에서도 필요한가?
- 컴포넌트의 재사용 가능성을 해치지 않는가?
- props로 관리할 수 없는 복잡한 구조나 다단계 전달이 필요한가?
추천글
'개발 공부 일지 > React' 카테고리의 다른 글
[React] 리액트 Router - 파라미터 & 쿼리 (0) | 2024.10.10 |
---|---|
[React] 리액트 Router란? (1) | 2024.10.09 |
[React] 리액트 useCallback란? (1) | 2024.10.06 |
[React] 제어 컴포넌트와 비제어 컴포넌트 (0) | 2024.10.04 |
[React] 리액트 useEffect란? (6) | 2024.10.01 |