리액트 프로젝트에서 전역적으로 사용할 데이터가 있을 때 유용한 기능
ex) 사용자 로그인 정보, 애플리케이션 환경 설정, 테마
Context API를 기반으로 구현된 것들
→ 리덕스, 리액트 라우터, styled-components
일반적인 전역 상태 관리 흐름)
ex) App이 지닌 state값을 F, J, G로 전달
F : App → A → B → F
J : App → H → J
G : App → A→ B → E → G.
를 거쳐야 한다.
Context API를 사용한 전역 상태 관리 흐름)
Context를 생성해 한 번에 어느 컴포넌트든 한 번에 원하는 값을 받아 와서 사용할 수 있다.
contexts/color.js)
import { createContext } from "react";
const ColorContext = createContext({ color: "black" });
export default ColorContext;
Consumer란?
Context 변화를 구독하는 React 컴포넌트
Consumer를 사용해 함수 컴포넌트 안에서 context를 구독할 수 있다.
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;
Render Props?
컴포넌트의 children이 있어야 할 자리에 일반 JSX 혹은 문자열이 아닌 함수를 전달하는 것
import React from "react";
import ColorBox from "./components/ColorBox";
const App = () => {
return (
<div>
<ColorBox />
</div>
);
};
export default App;
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값을 명시하지 않으면 기본값을 사용하지 않았기 때문에 오류가 발생한다.
import React from "react";
import ColorBox from "./components/ColorBox";
import ColorContext from "./contexts/color";
const App = () => {
return (
<ColorContext.Provider>
<div>
<ColorBox />
</div>
</ColorContext.Provider>
);
};
export default App;
context/color.js 수정 )
import { createContext } from "react";
const ColorContext = createContext({
state: { color: "black", subcolor: "yellow" },
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";
const App = () => {
return (
<ColorProvider>
<div>
<ColorBox />
</div>
</ColorProvider>
);
};
export default App;
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;
객체 비구조화 할당 문법을 사용해 value 조회 생략하기)
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;
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;
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>
<div>
style=
{{
width: "32px",
height: "32px",
background: state.subcolor,
}}
</div>
</>
);
};
export default ColorBox;
클래스형에서 Context를 더 쉽게 사용하고 싶다면, static contextType을 정의하는 방법이 있다.
SelectColors 컴포넌트를 클래스형으로 수정하기)
import React, { Component } from "react";
const colors = ["red", "orange", "yellow", "green", "blue", "indigo", "violet"];
class SelectColors extends Component {
render() {
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;
static contextType 값 지정하기)
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;
render() {
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;
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;
Q1) 한 번에 어느 컴포넌트든 한 번에 원하는 값을 받아 와서 사용할 수 있게 해주는 기능은?
Q2) 컴포넌트의 children이 있어야 할 자리에 일반 JSX 혹은 문자열이 아닌 함수를 전달하는 것
Q3) Hooks 중 Context를 더 쉽게 사용할 수 있게 해 주는 함수
Q4) 클래스형 컴포넌트에서 Context를 더 쉽게 사용할 수 있게 해 주는 함수
[리액트를 다루는 기술] 16장 리덕스 라이브러리 이해하기 (0) | 2022.01.17 |
---|---|
[리액트를 다루는 기술] 17장 리덕스를 사용하여 리액트 애플리케이션 상태 관리하기 (0) | 2022.01.17 |
[리액트를 다루는 기술] 14장 외부 API를 연동하여 뉴스 뷰어 만들기 (0) | 2022.01.03 |
[리액트를 다루는 기술]13장 리액트 라우터로 SPA 개발하기 (0) | 2021.12.27 |
[리액트를 다루는 기술] 12장 immer를 사용하여 더 쉽게 불변성 유지하기 (0) | 2021.12.27 |