// contexts/color.js
import { createContext } from "react";
const ColorContext = createContext({ color: "black" });
export default ColorContext;
// components/ColorBox.js
import ColorContext from "../contexts/color";
const ColorBox = () => {
<ColorContext.Consumer>
{(value) => (
<div
style={{
width: "64px",
height: "64px",
background: value.color,
}}
/>
)}
</ColorContext.Consumer>;
};
export default ColorBox;
Render Props (aka Function as a child)
예시<RenderPropsSample>{value => 2 * value}<RenderPropsSample/>
그럼 RenderPropsSample은 함수인 children을 부른다.
const RenderPropsSample = ({children}) => { return <div>{children(5)}</div>; } export default RenderPropsSample;
.
우리의 예제에서는ColorContext.Consumer
라는 component의 child가 function인 것!// ColorContext const ColorContext = createContext({ color: "black" });
// ColorBox Function Component의 Function Statement ()=>{요거} <ColorContext.Consumer> {(value) => (<div style={{(...)background: value.color,}}/>)} </ColorContext.Consumer>;
ColorContext.Consumer
의 function definition 에서createContext
에서 만든 context 객체를 argument로 다음과 같이 넣어서children({ color: "black" })
부르는 원리인 듯.
Provider 사용하면 Context의 value를 해당 컴포넌트 안에서 변경 가능하다.
// App.js
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 attribute 있어야 됨. 안그럼 runtime error.
- 이렇게 쓰면 해당 Provider안에서만
color:"red"
가 적용되는 것이지 context 자체 내용이 변하지는 않는다.
// color.js
import { 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;
export { ColorProvider, ColorConsumer };
export default ColorContext;
// ColorBox.js
import { ColorConsumer } from "../contexts/color";
const ColorBox = () => {
return (
<ColorConsumer>
{(
{ state } //`{(value) => (` 객체비구조화 할당으로 value 대신 그의 하위 객체인 state을 받아옴
) => (
<>
<div
style={{
width: "64px",
height: "64px",
background: state.color, //value.state.color,
}}
/>
<div
style={{
width: "32px",
height: "32px",
background: state.subcolor, //value.state.subcolor,
}}
/>
</>
)}
</ColorConsumer>
);
};
export default ColorBox;
// SelectColors.js
import { ColorConsumer } from "../contexts/color";
const ColorBox = () => {
return (
<ColorConsumer>
{(
{ state } //`{(value) => (` 객체비구조화 할당으로 value 대신 그의 하위 객체인 state을 받아옴
) => (
<>
<div
style={{
width: "64px",
height: "64px",
background: state.color, //value.state.color,
}}
/>
<div
style={{
width: "32px",
height: "32px",
background: state.subcolor, //value.state.subcolor,
}}
/>
</>
)}
</ColorConsumer>
);
};
export default ColorBox;
// App.js
import ColorBox from "./components/ColorBox";
import SelectColors from "./components/SelectColors";
import { ColorProvider } from "./contexts/color";
const App = () => {
return (
<>
<ColorProvider>
<div>
<SelectColors/>
<ColorBox />
</div>
</ColorProvider>
</>
);
};
export default App;
// Before
const ColorBox = () => {
return (
<ColorConsumer>
{({ state }) => (
<>(...)</>
// After
const ColorBox = () => {
const { state } = useContext(ColorContext);
return (
<>(...)</>
⚠️ Hook은 함수 컴포넌트 안에서만 사용가능
// 클래스형 컴포넌트 버전의 SelectColors.js
class SelectColors extends Component {
static contextType = ColorContext;
handleSetColor = color => {
this.context.actions.setColor(color);
}
handleSetSubcolor = subcolor => {
this.context.actions.setSubcolor(subColor);
}
render(){
return(
<div>
(...)
onClick{() => this.handleSetColor(color)}
onContextMenu{e => {
e.preventDefault();
this.handleSetSubcolor(color);
}}
</div>
)
}
}