Context API
- 리액트 프로젝트에서 전역적으로 사용할 데이터를 관리
- 사용자 로그인 정보, 애플리케이션 환경 설정, 테마 등
- 리덕스, 리액트 라우터, style-components 등이 Context API 기반으로 구현
Context API를 사용한 전역 상태 관리 흐름 이해하기
- 리액트 애플리케이션에서 전역적으로 사용할 데이터는 최상위 컴포넌트인
App
의state
에 넣어서 관리
전역 상태 관리 흐름
const [value, setValue] = useState('hello');
const onSetValue = useCallback(value => setValue(value), []);
- G 컴포넌트가 전역 상태를 업데이트 / F와 J 컴포넌트가 업데이트된 상태를 렌더링
App
이 지니고 있는value
값을 F와 J 컴포넌트에 전달App
-A
-B
-F
App
-H
-J
G
컴포넌트에 상태 업데이트 함수를 전달App
-A
-B
-E
-G
- 유지 보수성이 낮아짐
- Context API를 통하여 복잡한 경로를 거치지 않고 전역 상태를 관리
Context API 사용법 익히기
createContext
: 새로운 컨텍스트 생성
const ColorContext = createContext({ color: 'black '});
Consumer
: Context 내의 상태를 받아옴
const ColorBox = () => {
return (
<ColorContext.Consumer>
{value => (
<div
style= {{
width: '64px',
height: '64px',
background: value.color
}}
/>
)}
</ColorContext.Consumer>
);
} ;
Consumer
가ColorContext
내의color
를 사용함Provider
: Context 내의 상태를 변경함
const App = () => {
return (
<ColorContext.Provider value={{ color: 'red'}}>
<div>
<ColorBox />
</div>
</ColorContext.Provider>
);
};
ColorContext
내의color
가red
로 변경됨value
값을 명시하지 않을 경우 오류 발생
동적 Context 사용하기
createContext(value)
의value
로 함수를 전달할 수 있음
const ColorContext = createContext({
state: { color: 'black', subcolor: 'red' },
actions: {
setColor: () => {},
setSubcolor: () => {}
}
});
const ColorProvider = ({ children }) => {
const [color, setColor] = useState('black');
const [subcolor, setSubcolor] = useState('red');
const value = {
state: { color, subcolor },
actions: { setColor, setSubcolor }
};
return (
<ColorContext.Provider value={value}>{children}</ColorContext.Provider>
);
};
// const ColorConsumer = ColorContext.Consumer와 같은 읨
const { Consumer: ColorConsumer } = ColorContext;
// ColorProvider와 ColorConsumer 내보내기
export { ColorProvider, ColorConsumer };
export default ColorContext;
- 위와 같이 상태와 함수를 분리할 경우 다른 컴포넌트에서 Context 값을 사용하기 편리
Consumer 대신 Hook 또는 static contextType 사용하기
useContext
useContext
라는 Hook을 사용하여 함수 컴포넌트에서 Context를 편하게 사용 가능useContext
적용 전
const ColorBox = () => {
return (
<ColorConsumer>
{({ state }) => (
<>
<div
style={{
width: '64px',
height: '64px',
background: state.color
}}
/>
<div
style={{
width: '32px',
height: '32px',
background: state.subcolor
}}
/>
</>
)}
</ColorConsumer>
)
}
export default ColorBox;
useContext
적용 후
const ColorBox = () => {
const { state } = useContext(ColorContext);
return (
<>
<div
style={{
width: '64px',
height: '64px',
background: state.color
}}
/>
<div
style={{
width: '32px',
height: '32px',
background: state.subcolor
}}
/>
</>
)
}
export default ColorBox;
children
에 함수를 전달하는 Render Props 패턴 대신 간결하게 Context 조회 가능
Render Props 패턴?
- 컴포넌트의 children이 있어야 할 자리에 함수를 전달
- https://reactjs.org/docs/render-props.html
const RenderPropsSample = ({ children }) => {
return <div>결과: {children(5)}</div>;
}
<RenderPropsSample>{value => 2 * value}</RenderPropsSample>
// 결과: 10
static contextType
static contextType
을 사용하여 클래스형 컴포넌트에서 Context를 좀 더 쉽게 사용할 수 있음
class SelectColors extends Component {
static contextType = ColorContext;
handleSetColor = color => {
this.context.actions.setColor(color);
}
}
- 한 클래스에서 하나의 Context 만을 사용할 수 있으므로 함수형 컴포넌트와
useContext
를 사용하는 것을 권장
정리
- 기존에는 컴포넌트 간에 상태를 교류할 때 무조건 props를 통해 전달해야 했음
- Context API를 이용하여 더욱 쉽게 상태를 교류하는 것이 가능
- 단순한 전역 상태 관리에서는 Context API를 사용해도 되지만 대부분의 경우 리덕스를 사용하는 것을 권장