๐ŸŽ‰ berenickt ๋ธ”๋กœ๊ทธ์— ์˜จ ๊ฑธ ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค. ๐ŸŽ‰
Front
Context API

1. State Management(์ƒํƒœ๊ด€๋ฆฌ)

14์—์„œ ์“ด Context ๋ณต์Šต

1.1 Prop Drilling (Props๋กœ๋งŒ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•˜๋ฉด ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ)

React_14_2

Prop Drilling = Props๋กœ๋งŒ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•˜๋ฉด ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ

์ผ๋ฐ˜์ ์œผ๋กœ ์ปดํฌ๋„ŒํŠธ์—๊ฒŒ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•ด์ฃผ์–ด์•ผ ํ•  ๋•Œ Props๋ฅผ ํ†ตํ•ด ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.

1
export default function App() {
2
return <GrandParent value="Hello World!" />
3
}
4
5
function Parent({ value }) {
6
return <Child value={value} />
7
}
8
9
function Child({ value }) {
10
return <Message value={value} />
11
}
12
13
function Message({ value }) {
14
return <div>Received: {value}</div>
15
}

๊ทธ๋Ÿฐ๋ฐ ์ž์‹์ด ๋งŽ์€ ์ปดํฌ๋„ŒํŠธ์— ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ, ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ฑฐ์ณ ์—ฐ๋‹ฌ์•„์„œ Props๋ฅผ ์„ค์ •ํ•ด์ฃผ์–ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ถˆํŽธํ•˜๊ณ  ์‹ค์ˆ˜ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ€๋Šฅ์„ฑ์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ๋งŽ์€ ์ž์‹์„ ๊ฐ€์ง„ ์ปดํฌ๋„ŒํŠธ์— state๊ฐ’์„ ์ „๋‹ฌํ•˜๋ ค๋ฉด Context๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

Context API (๋ฆฌ์•กํŠธ ๊ธฐ๋ณธ ๋ฌธ๋ฒ•)

  • props ์ „์†ก์—†์ด state ๊ณต์œ  ๊ฐ€๋Šฅ
  • 2๊ฐ€์ง€ ๋ฌธ์ œ ๋•Œ๋ฌธ์— ๋งŽ์ด ์“ฐ์ด์ง€ ์•Š์Œ
    • state ๋ณ€๊ฒฝ์‹œ ์“ธ๋ฐ์—†๋Š” ์ปดํฌ๋„ŒํŠธ๊นŒ์ง€ ์ „๋ถ€ ์žฌ๋ Œ๋”๋ง๋˜์–ด ์„ฑ๋Šฅ ์ด์Šˆ
    • ์ปดํฌ๋„ŒํŠธ ์žฌํ™œ์šฉ์ด ์–ด๋ ค์›€
  • Context API๋ณด๋‹ค๋Š” redux๊ฐ™์€ ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋งŽ์ด ์‚ฌ์šฉ
  • Official React Context Docsโœ”๏ธ

2. Context API

  • ๋ฆฌ์•กํŠธ ๊ธฐ๋ณธ ๋ฌธ๋ฒ•

  • context = state ๋ณด๊ด€ํ•จ

  • props ์—†์ด state ๊ณต์œ ํ•  ๋•Œ ์‚ฌ์šฉํ•˜์ง€๋งŒ, ์„ฑ๋Šฅ๊ณผ ์žฌํ™œ์šฉ ๊ด€์ ์—์„œ ๋ฌธ์ œ๊ฐ€ ์žˆ์–ด์„œ ๋งŽ์ด ์‚ฌ์šฉ ์•ˆํ•จ

    • state ๋ณ€๊ฒฝ์‹œ ์“ธ๋ฐ์—†๋Š” ์ปดํฌ๋„ŒํŠธ๊นŒ์ง€ ์ „๋ถ€ ์žฌ๋ Œ๋”๋ง๋˜์–ด ์„ฑ๋Šฅ ์ด์Šˆ
    • useContext()๋ฅผ ์“ฐ๊ณ  ์žˆ๋Š” ์ปดํฌ๋„ŒํŠธ๋Š” ๋‚˜์ค‘์— ๋‹ค๋ฅธ ํŒŒ์ผ์—์„œ ์žฌ์‚ฌ์šฉํ•  ๋•Œ Context๋ฅผ import ํ•˜๋Š”๊ฒŒ ๊ท€์ฐฎ์Œ
  • ์œ„ ๋ฌธ์ œ๋“ค๋กœ ์ธํ•ด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•จ

  • React v16.3๋ถ€ํ„ฐ ์‚ฌ์šฉํ•˜๊ธฐ ์‰ฝ๊ฒŒ ๋งŽ์ด ๊ฐœ์„ ๋จ

    • ๊ณผ๊ฑฐ์—๋Š” ๋ฆฌ์•กํŠธ์˜ Context๊ฐ€ ๊ต‰์žฅํžˆ ๋ถˆํŽธํ•ด์„œ ์ „์—ญ ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ–ˆ์—ˆ์Œ
    • ์ด์ œ๋Š” Context๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ํŽธํ•ด์ ธ์„œ ๋‹จ์ˆœํžˆ ์ „์—ญ์ ์ธ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•จ์ด๋ผ๋ฉด ๋” ์ด์ƒ ์‚ฌ์šฉํ•ด์•ผ ํ•  ์ด์œ  X
    • ๊ทธ๋ ‡์ง€๋งŒ ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ์ƒํƒœ ๊ด€๋ฆฌ๋ฅผ ๋”์šฑ ํŽธํ•˜๊ณ , ํšจ์œจ์ ์œผ๋กœ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ๊ธฐ๋Šฅ๋“ค์„ ์ œ๊ณต
  • Redux, ๋ฆฌ์•กํŠธ ๋ผ์šฐํ„ฐ, styled-components ๋“ฑ์˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์€ Context API๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๊ตฌํ˜„๋˜์–ด ์žˆ์Œ

  • ์ค‘์ฒฉํ•ด์„œ ์‚ฌ์šฉํ•œ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋งŽ์„ ๋•Œ ํŽธ๋ฆฌํ•œ ๋ฌธ๋ฒ•

    • e.g. ๋กœ๊ทธ์ธํ•œ ์œ ์ € ์ •๋ณด, ํ…Œ๋งˆ(๋‹คํฌ ํ…Œ๋งˆ), ์„ ํ˜ธํ•˜๋Š” ์–ธ์–ด ๋“ฑ
  • Context์—์„œ ๋‹ค๋ฃจ๋Š” ๊ฐ’์€ ๊ผญ ์ „์—ญ์ ์ผ ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

    • Context๋Š” ์žฌ์‚ฌ์šฉ์„ฑ์ด ๋†’์€ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค๋•Œ๋„ ๋งค์šฐ ์œ ์šฉํ•จ
  • ์ค‘์ฒฉ๋œ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ ์œผ๋ฉด ๊ทธ๋ƒฅ props์“ฐ๋Š”๊ฒŒ ํŽธํ•จ

  • c.f. Velog - ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค์ด ์•ˆ ์•Œ๋ ค์ฃผ๋Š” ๋ฆฌ์•กํŠธ์—์„œ Context API ์ž˜ ์“ฐ๋Š” ๋ฐฉ๋ฒ•

  • cf. Velopert - Velog ๋ฆฌ์•กํŠธ์—์„œ Context API ์ž˜ ์“ฐ๋Š” ๋ฒ•


2.1 ์˜ˆ์ œ 1 : Context ๊ธฐ๋ณธ ์‚ฌ์šฉ๋ฒ•

1
import { createContext, useContext } from 'react'
2
3
// 1. Context ๋งŒ๋“ค๊ธฐ
4
// - createContext()๋กœ Context ๋งŒ๋“ค ์ˆ˜ ์žˆ์Œ
5
// - ๊ธฐ๋ณธ ๊ฐ’์„ ์„ค์ •ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด, createContext ํ•จ์ˆ˜์— ์ธ์ž๋กœ ๊ธฐ๋ณธ ๊ฐ’์„ ๋„ฃ์–ด์ฃผ๋ฉด ๋จ
6
const MyContext = createContext('๊ธฐ๋ณธ๊ฐ’')
7
8
export default function App() {
9
// 2. Context ๊ฐ์ฒด ์•ˆ์—๋Š” Provider๋ผ๋Š” ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋“ค์–ด์žˆ์Œ
10
// Provider ์ปดํฌ๋„ŒํŠธ์— ๊ณต์œ ํ•˜๊ณ ์ž ํ•˜๋Š” ๊ฐ’์„ value ๋ผ๋Š” Props๋กœ ์„ค์ •ํ•˜๋ฉด,
11
// ์ž์‹ ์ปดํฌ๋„ŒํŠธ๋“ค์—์„œ ํ•ด๋‹น ๊ฐ’์— ๋ฐ”๋กœ ์ ‘๊ทผ ๊ฐ€๋Šฅ
12
return (
13
<>
14
<MyContext.Provider value="Hello World">
15
<Parent />
16
</MyContext.Provider>
17
<Parent />
18
</>
19
)
20
}
21
22
function Parent() {
23
return <Child />
24
}
25
26
function Child() {
27
return <Message />
28
}
29
30
function Message() {
31
// 3. Context ์•ˆ์— ์žˆ๋˜ state ์‚ฌ์šฉํ•˜๋ ค๋ฉด, useContext() ์‚ฌ์šฉ
32
// - useContext() : Context ํ•ด์ฒดํ•ด์ฃผ๋Š” ํ•จ์ˆ˜, ๊ณต์œ ํ–ˆ๋˜ ๋ชจ๋“  state๊ฐ€ ๋‹ด๊ฒจ์žˆ์Œ
33
const value = useContext(MyContext)
34
return <div>๋ฐ์ดํ„ฐ ๋„์ฐฉํ•จ!๐Ÿ˜ : {value}</div>
35
}

2.2 ์˜ˆ์ œ 2 : Dark Theme

2.2.1 Context ์ƒ์„ฑ

1
// Context/ThemeContext.js
2
import React from 'react'
3
4
export const themes = {
5
light: {
6
foreground: '#000000',
7
background: '#eeeeee',
8
},
9
dark: {
10
foreground: '#ffffff',
11
background: '#222222',
12
},
13
}
14
15
// createContext()๋กœ Context ๋งŒ๋“ค ์ˆ˜ ์žˆ์Œ
16
export const ThemeContext = React.createContext(themes.dark)

์ƒˆ Context๋ฅผ ๋งŒ๋“ค ๋•Œ๋Š” createContext ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ํŒŒ๋ผ๋ฏธํ„ฐ์—๋Š” ํ•ด๋‹น Context์˜ ๊ธฐ๋ณธ ์ƒํƒœ๋ฅผ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.

  • c.f. Context๋ฅผ ๋งŒ๋“ค ๋•Œ ๋ฐ˜๋“œ์‹œ contexts ๋””๋ ‰ํ„ฐ๋ฆฌ์— ๋งŒ๋“ค ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค. ๊ฒฝ๋กœ๋Š” ๋งˆ์Œ๋Œ€๋กœ ์ •ํ•ด๋„ ๋จ

2.2.2 Provider

1
// Context/Example
2
import React, { Component } from 'react'
3
import ThemeButton from './ThemeButton'
4
import { ThemeContext, themes } from './ThemeContext'
5
6
export default class Example extends Component {
7
constructor(props) {
8
super(props)
9
this.state = {
10
theme: themes.light,
11
}
12
this.toggleTheme = () => {
13
this.setState(prev => ({
14
theme: prev.theme === themes.dark ? themes.light : themes.dark,
15
}))
16
}
17
}
18
render() {
19
// ๐Ÿ“ Context์— ์ €์žฅ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด, Context์˜ Provider๋ฅผ ์‚ฌ์šฉ
20
// - ๊ณต์œ ๋ฅผ ์›ํ•˜๋Š” state๋ฅผ value ์•ˆ์— ์ ์–ด์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.
21
// - ThemeContext๋กœ ๊ฐ์‹ผ ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ์™€ ๊ทธ ์ž์‹์ปดํฌ๋„ŒํŠธ๋Š” state๋ฅผ props ์ „์†ก์—†์ด ์ง์ ‘ ์‚ฌ์šฉ๊ฐ€๋Šฅ
22
// ๐Ÿ“ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋Š” ์ปดํฌ๋„ŒํŠธ์—์„œ Context์˜ Consumer๋ฅผ ์‚ฌ์šฉ โ†’ useContext()๋กœ ๋Œ€์ฒด ๊ฐ€๋Šฅ
23
return (
24
<div>
25
<ThemeContext.Provider value={this.state.theme}>
26
<ThemeButton changeTheme={this.toggleTheme} />
27
<ThemeContext.Consumer>
28
{theme => (
29
<div
30
style={{
31
height: 300,
32
width: 300,
33
backgroundColor: theme.background,
34
}}
35
></div>
36
)}
37
</ThemeContext.Consumer>
38
</ThemeContext.Provider>
39
<ThemeButton />
40
</div>
41
)
42
}
43
}

2.2.3 useContext()

1
// context/ThemeButton.jsx
2
import React, { useContext } from 'react'
3
import { ThemeContext } from './ThemeContext'
4
5
export default function ThemeButton(props) {
6
// Context ์•ˆ์— ์žˆ๋˜ state ์‚ฌ์šฉํ•˜๋ ค๋ฉด
7
// (1) ๋งŒ๋“ค์–ด๋‘” Context๋ฅผ import
8
// (2) useContext() ์•ˆ์— ๋„ฃ๊ธฐ
9
// -- useContext()๋Š” Context ํ•ด์ฒดํ•ด์ฃผ๋Š” ํ•จ์ˆ˜, ๊ณต์œ ํ–ˆ๋˜ ๋ชจ๋“  state๊ฐ€ ๋‹ด๊ฒจ์žˆ์Œ
10
const theme = useContext(ThemeContext)
11
return (
12
<button
13
{...props}
14
onClick={props.changeTheme}
15
style={{ backgroundColor: theme.background, color: theme.foreground }}
16
>
17
๋ฒ„ํŠผ
18
</button>
19
)
20
}

App ์ปดํฌ๋„ŒํŠธ์— ์ถ”๊ฐ€

1
import Example from './components/3-10_Context/Example'
2
3
export default function App() {
4
return (
5
<>
6
<Example />
7
</>
8
)
9
}

[์ฐธ๊ณ ]