- 전역적으로 사용할 데이터가 있을 때 유용한 기능
- ex) 사용자 로그인 정보, 애플리케이션 환경 설정, 테마 등
- 리액트 관련 라이브러리에서도 많이 사용
- ex) 리덕스, 리액트 라우터, styled-components등
1. Context API를 사용한 전역 상태 관리 흐름 이해하기
- 컴포넌트 간에 데이터를 props로 전달하기 때문에 여기저기서 필요한 데이터가 있을 때는 주로 최상위 컴포넌트인 App의 state에 넣어 관리
- 기존엔 최상위 컴포넌트에서 여러 컴포넌트를 거쳐 props로 원하는 상태와 함수를 전달했지만, Context API를 사용하면 Context를 만들어 단 한 번에 원하는 값을 받아 와서 사용할 수 있다.
2. Context API 사용법 익히기
2.1. 새 Context 만들기
[contexts/color.js]
import {createContext} from 'react';
const ColorContext = createContext({ color: 'black' });
export default ColorContext
2.2. Consumer 사용하기
- ColorContext안에 들어있는 색상을 보여줄 것이다.
- 색상을 props로 받아 오는 것이 아니라 ColorContext 안에 들어 있는 Consumer 라는 컴포넌트를 통해 조회할 것
[components/ColorBox.js]
import React from 'react';
import ColorContext from '../contexts/color'
const ColorBox = () => {
return (
<ColorContext.Consumer>
{value => (
<div
style={{
width: '64px',
height: '64px',
background: value.color
}}
/>
)}
</ColorContext.Consumer>
);
};
export default ColorBox
- Consumer 사이에 중괄호를 열어서 그 안에 함수를 넣어줬다.
- 이러한 패턴을 Function as a child, 혹은 Render Props라고 한다.
- 컴포넌트의 child가 있어야 할 자리에 일반 JSX 혹은 문자열이 아닌 함수를 전달 하는 것
[App.js]
import React from 'react';
import ColorBox from './components/ColorBox';
const App = () => {
return (
<div>
<ColorBox />
</div>
);
};
export default App;
[결과]
2.3. Provider
- Context의 value를 변경할 수 있다.
[App.js]
import React from 'react';
import ColorBox from './components/ColorBox';
import ColorContext from './contexts/color'
const App = () => {
return (
<ColorContext.Provider value={{color: 'red'}}>
<div>
<ColorBox />
</div>
</ColorContext.Provider>
);
};
export default App;
- 만약 Provider는 사용했는데 value를 명시하지 않았다면, 오류발생
[결과]
3. 동적 Context 사용하기
Context의 value에는 무조건 상태값만 있어야 하는 것은 아니다. 함수를 전달해 줄 수도 있다.
[contents/color.js]
import React, {createContext, useState} from 'react';
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
- Provider의 value 상태는 state로, 업데이트 함수는 actions로 묶어서 전달하고 있다.
- 따로 분리해주면 나중에 다른 컴포넌트에서 Context의 값을 사용할 때 편하다.
- createContext의 기본값을 실제 Provider의 value에 넣는 객체의 형태와 일치시켜 주는 것이 좋다.
- 내부 값이 어떻게 구성되어 있는지 파악하기 쉽고, 실수로 Provider를 사용하지 않았을 때 에러발생하지 않음.
[App.js]
import React from 'react';
import ColorBox from './components/ColorBox';
import {ColorProvider} from './contexts/color'
const App = () => {
return (
<ColorProvider>
<div>
<ColorBox />
</div>
</ColorProvider>
);
};
export default App;
- ColorContext.Provider를 ColorProvider로 대체
[components/ColorBox.js]
import React from 'react';
import {ColorConsumer} from '../contexts/color'
const ColorBox = () => {
return (
<ColorConsumer>
{value => (
<>
<div
style={{
width: '64px',
height: '64px',
background: value.state.color
}}
/>
<div
style={{
width: '32px',
height: '32px',
background: value.state.subcolor
}}
/>
</>
)}
</ColorConsumer>
);
};
export default ColorBox
- ColorContext.Consumer 를 ColorConsumer로 변경
- 위 코드에서 객체 비구조화 할당 문법을 사용하면 다음과 같이 value를 조회하는 것을 생략할 수 있다.
[components/ColorBox.js]
import React from 'react';
import {ColorConsumer} from '../contexts/color'
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
[결과]
3.3.색상 선택 컴포넌트 만들기
- Context의 actions에 넣어 준 함수를 호출하는 컴포넌트를 만들어 보겠다.
[components/SelectColors.js]
import React from 'react';
const colors = ['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet'];
const SelectColors = () => {
return (
<div>
<h2>색상을 선택하세요.</h2>
<div style={{ display: 'flex' }}>
{colors.map(color => (
<div
key={color}
style={{
background: color,
width: '24px',
height: '24px',
cursor: 'pointer'
}}
/>
))}
</div>
<hr />
</div>
);
};
export default SelectColors;
[App.js]
import React from 'react';
import ColorBox from './components/ColorBox';
import {ColorProvider} from './contexts/color'
import SelectColors from './components/SelectColors'
const App = () => {
return (
<ColorProvider>
<div>
<SelectColors />
<ColorBox />
</div>
</ColorProvider>
);
};
export default App;
[결과]
- 이제 마우스 왼쪽 버튼을 클릭하면 큰 정사각형의 색상을 변경하고, 마우스 오른쪽 버튼을 클릭하면 작은 정사각형의 색상을 변경하도록 구현해 보겠다.
[components/SelectColors.js]
import React from 'react';
import { ColorConsumer } from '../contexts/color'
const colors = ['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet'];
const SelectColors = () => {
return (
<div>
<h2>색상을 선택하세요.</h2>
<ColorConsumer>
{({actions}) => (
<div style={{ display: 'flex' }}>
{colors.map(color => (
<div
key={color}
style={{
background: color,
width: '24px',
height: '24px',
cursor: 'pointer'
}}
onClick={() => actions.setColor(color)}
onContextMenu={ e => {
e.preventDefault(); //마우스 오른쪽 버튼 클릭 시 메뉴가 뜨는 것을 무시함
actions.setSubcolor(color)
}}
/>
))}
</div>
)}
</ColorConsumer>
<hr />
</div>
);
};
export default SelectColors;
[결과]
4. Consumer 대신 Hook 또는 static contextType 사용하기
4.1. useContext Hook 사용하기
- 리액트에 내장되어 있는 Hooks 중에서 useContext라는 Hook을 사용하면, 함수형 컴포넌트에서 Context를 아주 편하게 사용할 수 있다.
[components/ColorBox.js]
import React, { useContext } from 'react';
import ColorContext from '../contexts/color'
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패턴이 불편하다면, useContext Hooks을 사용하여 훨씬 편하게 Context 값을 조회할 수 있다.
- 그러나 Hook은 함수형 컴포넌트에서만 사용할 수 있다.
4.2. static contextType 사용하기
- 클래스형 컴포넌트에서 Context를 좀 더 쉽게 사용하고 싶을 때 사용
[components/SelectColors.js]
import React, {Component} from 'react';
import ColorContext from '../contexts/color'
const colors = ['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet'];
class SelectColors extends Component {
static contextType = ColorContext
handleSetColor = color => {
this.context.actions.setColor(color);
};
handleSetSubcolor = subcolor => {
this.context.actions.setSubcolor(subcolor);
};
render() {
return (
<div>
<h2>색상을 선택하세요.</h2>
<div style={{ display: 'flex' }}>
{colors.map(color => (
<div
key={color}
style={{
background: color,
width: '24px',
height: '24px',
cursor: 'pointer'
}}
onClick={() => this.handleSetColor(color)}
onContextMenu={e => {
e.preventDefault();
this.handleSetSubcolor(color)
}}
/>
))}
</div>
<hr />
</div>
);
}
};
export default SelectColors;
'Front > React' 카테고리의 다른 글
[React] 리덕스를 사용하여 리액트 애플리케이션 상태 관리하기 (0) | 2021.01.16 |
---|---|
[React] 리덕스 라이브러리 (0) | 2021.01.14 |
[React] 외부 API를 연동하여 뉴스 뷰어 만들기 (0) | 2021.01.12 |
[React] 리액트 라우터 부가 기능 (0) | 2021.01.09 |
[React] 서브 라우트 (0) | 2021.01.09 |