디자인 패턴 중 상태 패턴은 Context 클래스에서 인터페이스를 제공하여 State로 캡슐화하는 것을 의미한다.
참조
리액트에서의 Context는 전역적(global)으로 데이터를 공유하기 위해 사용되도록 디자인되었다. 즉 데이터 간의 간격과 컴포넌트 트리의 계층이 없이 데이터를 공유할 수 있다. 16.3버전부터 추가되었다.
context 안에 {color: 'black'}
이라는 값을 넣어 해당 값을 전역적으로 사용하는 예제이다.
import { createContext } from "react";
const ColorContext = createContext({ color: "black" });
export default ColorContext;
import ColorContext from "../contexts/color";
const ColorBox = () => {
return (
<ColorContext.Consumer>
{(value) => (
<div
style={{
width: "64px",
height: "64px",
background: value.color, //color: 'black'
}}
/>
)}
</ColorContext.Consumer>
);
};
@/App.js
import ColorBox from "./components/ColorBox";
import ColorContext from "./comtexts/color";
const App = () => {
return (
<ColorContext.Provider value={{ color: "red" }}>
<div>
<ColorBox />
</div>
</ColorContext.Provider>
);
};
export default App;
Context는 함수 등 다양한 값을 지니고 있을 수 있다.
아래는 조금 더 복잡한 예시이다.
@/contexts/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;
@/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;
ColorContext 모듈의 state를 구조분해 할당으로 가져온 예시이다.
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;
클래스형 컴포넌트 컴포넌트명.contextType을 통하여 this.context에 createContext()로 생성된 컨텍스트를 바인딩할 수 있다.
이 경우 하나의 context만 바인딩 됨에 유의하자.
(여러 컨텍스트를 사용하는 경우 CONTEXT.Provider를 통해 프로퍼티를 넘겨주어야 한다.)
Babel을 통해서 Static 클래스 필드를 사용하면 아래와 같이 정의할 수 있다.
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;