Context
context๋ฅผ ์ด์ฉํ๋ฉด ๋จ๊ณ๋ง๋ค ์ผ์ผ์ด props๋ฅผ ๋๊ฒจ์ฃผ์ง ์๊ณ ๋ ์ปดํฌ๋ํธ ํธ๋ฆฌ ์ ์ฒด์ ๋ฐ์ดํฐ๋ฅผ ์ ๊ณตํ ์ ์์ต๋๋ค.
์ผ๋ฐ์ ์ธ React ์ ํ๋ฆฌ์ผ์ด์ ์์ ๋ฐ์ดํฐ๋ ์์์ ์๋๋ก (์ฆ, ๋ถ๋ชจ๋ก๋ถํฐ ์์์๊ฒ) props๋ฅผ ํตํด ์ ๋ฌ๋์ง๋ง, ์ ํ๋ฆฌ์ผ์ด์ ์์ ์ฌ๋ฌ ์ปดํฌ๋ํธ๋ค์ ์ ํด์ค์ผ ํ๋ props์ ๊ฒฝ์ฐ (์๋ฅผ ๋ค๋ฉด ์ ํธ ๋ก์ผ์ผ, UI ํ ๋ง) ์ด ๊ณผ์ ์ด ๋ฒ๊ฑฐ๋ก์ธ ์ ์์ต๋๋ค. context๋ฅผ ์ด์ฉํ๋ฉด, ํธ๋ฆฌ ๋จ๊ณ๋ง๋ค ๋ช ์์ ์ผ๋ก props๋ฅผ ๋๊ฒจ์ฃผ์ง ์์๋ ๋ง์ ์ปดํฌ๋ํธ๊ฐ ์ด๋ฌํ ๊ฐ์ ๊ณต์ ํ๋๋ก ํ ์ ์์ต๋๋ค.
์ธ์ context๋ฅผ ์จ์ผ ํ ๊น
context๋ React ์ปดํฌ๋ํธ ํธ๋ฆฌ ์์์ ์ ์ญ์ (global)์ด๋ผ๊ณ ๋ณผ ์ ์๋ ๋ฐ์ดํฐ๋ฅผ ๊ณต์ ํ ์ ์๋๋ก ๊ณ ์๋ ๋ฐฉ๋ฒ์ ๋๋ค. ๊ทธ๋ฌํ ๋ฐ์ดํฐ๋ก๋ ํ์ฌ ๋ก๊ทธ์ธํ ์ ์ , ํ ๋ง, ์ ํธํ๋ ์ธ์ด ๋ฑ์ด ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, ์๋์ ์ฝ๋๋ ๋ฒํผ ์ปดํฌ๋ํธ๋ฅผ ๊พธ๋ฏธ๊ธฐ ์ํด ํ ๋ง(theme) props๋ฅผ ๋ช ์์ ์ผ๋ก ๋๊ฒจ์ฃผ๊ณ ์์ต๋๋ค.
class App extends React.Component {
render() {
return <Toolbar theme="dark" />;
}
}
function Toolbar(props) {
// Toolbar ์ปดํฌ๋ํธ๋ ๋ถํ์ํ ํ
๋ง prop๋ฅผ ๋ฐ์์ // ThemeButton์ ์ ๋ฌํด์ผ ํฉ๋๋ค. // ์ฑ ์์ ๋ชจ๋ ๋ฒํผ์ด ํ
๋ง๋ฅผ ์์์ผ ํ๋ค๋ฉด // ์ด ์ ๋ณด๋ฅผ ์ผ์ผ์ด ๋๊ธฐ๋ ๊ณผ์ ์ ๋งค์ฐ ๊ณคํน์ค๋ฌ์ธ ์ ์์ต๋๋ค. return (
<div>
<ThemedButton theme={props.theme} /> </div>
);
}
class ThemedButton extends React.Component {
render() {
return <Button theme={this.props.theme} />;
}
}
context๋ฅผ ์ฌ์ฉํ๋ฉด ์ค๊ฐ์ ์๋ ์๋ฆฌ๋จผํธ๋ค์๊ฒ props๋ฅผ ๋๊ฒจ์ฃผ์ง ์์๋ ๋ฉ๋๋ค.
// context๋ฅผ ์ฌ์ฉํ๋ฉด ๋ชจ๋ ์ปดํฌ๋ํธ๋ฅผ ์ผ์ผ์ด ํตํ์ง ์๊ณ ๋// ์ํ๋ ๊ฐ์ ์ปดํฌ๋ํธ ํธ๋ฆฌ ๊น์ํ ๊ณณ๊น์ง ๋ณด๋ผ ์ ์์ต๋๋ค.// light๋ฅผ ๊ธฐ๋ณธ๊ฐ์ผ๋ก ํ๋ ํ
๋ง context๋ฅผ ๋ง๋ค์ด ๋ด
์๋ค.const ThemeContext = React.createContext('light');
class App extends React.Component {
render() {
// Provider๋ฅผ ์ด์ฉํด ํ์ ํธ๋ฆฌ์ ํ
๋ง ๊ฐ์ ๋ณด๋ด์ค๋๋ค. // ์๋ฌด๋ฆฌ ๊น์ํ ์์ด๋, ๋ชจ๋ ์ปดํฌ๋ํธ๊ฐ ์ด ๊ฐ์ ์ฝ์ ์ ์์ต๋๋ค. // ์๋ ์์์์๋ dark๋ฅผ ํ์ฌ ์ ํ๋ ํ
๋ง ๊ฐ์ผ๋ก ๋ณด๋ด๊ณ ์์ต๋๋ค. return (
<ThemeContext.Provider value="dark"> <Toolbar />
</ThemeContext.Provider>
);
}
}
// ์ด์ ์ค๊ฐ์ ์๋ ์ปดํฌ๋ํธ๊ฐ ์ผ์ผ์ด ํ
๋ง๋ฅผ ๋๊ฒจ์ค ํ์๊ฐ ์์ต๋๋ค.function Toolbar() { return (
<div>
<ThemedButton />
</div>
);
}
class ThemedButton extends React.Component {
// ํ์ฌ ์ ํ๋ ํ
๋ง ๊ฐ์ ์ฝ๊ธฐ ์ํด contextType์ ์ง์ ํฉ๋๋ค. // React๋ ๊ฐ์ฅ ๊ฐ๊น์ด ์๋ ํ
๋ง Provider๋ฅผ ์ฐพ์ ๊ทธ ๊ฐ์ ์ฌ์ฉํ ๊ฒ์
๋๋ค. // ์ด ์์์์ ํ์ฌ ์ ํ๋ ํ
๋ง๋ dark์
๋๋ค. static contextType = ThemeContext;
render() {
return <Button theme={this.context} />; }
}
context๋ฅผ ์ฌ์ฉํ๊ธฐ ์ ์ ๊ณ ๋ คํ ๊ฒ
context์ ์ฃผ๋ ์ฉ๋๋ ๋ค์ํ ๋ ๋ฒจ์ ๋ค์คํ ๋ ๋ง์ ์ปดํฌ๋ํธ์๊ฒ ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํ๋ ๊ฒ์ ๋๋ค. context๋ฅผ ์ฌ์ฉํ๋ฉด ์ปดํฌ๋ํธ๋ฅผ ์ฌ์ฌ์ฉํ๊ธฐ๊ฐ ์ด๋ ค์์ง๋ฏ๋ก ๊ผญ ํ์ํ ๋๋ง ์ฐ์ธ์.
์ฌ๋ฌ ๋ ๋ฒจ์ ๊ฑธ์ณ props ๋๊ธฐ๋ ๊ฑธ ๋์ฒดํ๋ ๋ฐ์ context๋ณด๋ค ์ปดํฌ๋ํธ ํฉ์ฑ์ด ๋ ๊ฐ๋จํ ํด๊ฒฐ์ฑ ์ผ ์๋ ์์ต๋๋ค.
์๋ฅผ ๋ค์ด ์ฌ๋ฌ ๋จ๊ณ ์๋์ ์๋ Link
์ Avatar
์ปดํฌ๋ํธ์๊ฒ user
์ avatarSize
๋ผ๋ props๋ฅผ ์ ๋ฌํด์ผ ํ๋ Page
์ปดํฌ๋ํธ๋ฅผ ์๊ฐํด๋ด
์๋ค.
<Page user={user} avatarSize={avatarSize} />
// ... ๊ทธ ์๋์ ...
<PageLayout user={user} avatarSize={avatarSize} />
// ... ๊ทธ ์๋์ ...
<NavigationBar user={user} avatarSize={avatarSize} />
// ... ๊ทธ ์๋์ ...
<Link href={user.permalink}>
<Avatar user={user} size={avatarSize} />
</Link>
์ค์ ๋ก ์ฌ์ฉ๋๋ ๊ณณ์ Avatar
์ปดํฌ๋ํธ ๋ฟ์ธ๋ฐ user
์ avatarSize
props๋ฅผ ์ฌ๋ฌ ๋จ๊ณ์ ๊ฑธ์ณ ๋ณด๋ด์ค์ผ ํ๋ค๋ ๊ฒ ๋ฒ๊ฑฐ๋ก์ ๋ณด์ผ ์ ์์ต๋๋ค. ๊ฒ๋ค๊ฐ ์์์ Avatar
์ปดํฌ๋ํธ๋ก ๋ณด๋ด์ค์ผํ๋ props๊ฐ ์ถ๊ฐ๋๋ค๋ฉด ๊ทธ ๋ํ ์ค๊ฐ ๋ ๋ฒจ์ ๋ชจ๋ ์ถ๊ฐํด์ค์ผ ํฉ๋๋ค.
Avatar
์ปดํฌ๋ํธ ์์ฒด๋ฅผ ๋๊ฒจ์ฃผ๋ฉด context๋ฅผ ์ฌ์ฉํ์ง ์๊ณ ์ด๋ฅผ ํด๊ฒฐํ ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋ฉด ์ค๊ฐ์ ์๋ ์ปดํฌ๋ํธ๋ค์ด user
๋ avatarSize
์ ๋ํด ์ ํ ์ ํ์๊ฐ ์์ต๋๋ค.
function Page(props) {
const user = props.user;
const userLink = (
<Link href={user.permalink}>
<Avatar user={user} size={props.avatarSize} />
</Link>
);
return <PageLayout userLink={userLink} />;
}
// ์ด์ ์ด๋ ๊ฒ ์ธ ์ ์์ต๋๋ค.
<Page user={user} avatarSize={avatarSize} />
// ... ๊ทธ ์๋์ ...
<PageLayout userLink={...} />
// ... ๊ทธ ์๋์ ...
<NavigationBar userLink={...} />
// ... ๊ทธ ์๋์ ...
{props.userLink}
์ด๋ ๊ฒ ๋ฐ๊พธ๋ฉด Link
์ Avatar
์ปดํฌ๋ํธ๊ฐ user
์ avatarSize
props๋ฅผ ์ด๋ค๋ ๊ฑธ ์์์ผ ํ๋ ๊ฑด ๊ฐ์ฅ ์์ ์๋ Page
๋ฟ์
๋๋ค.
์ด๋ฌํ ์ ์ด์ ์ญ์ (inversion of control) ์ ์ด์ฉํ๋ฉด ๋๊ฒจ์ค์ผ ํ๋ props์ ์๋ ์ค๊ณ ์ต์์ ์ปดํฌ๋ํธ์ ์ ์ด๋ ฅ์ ๋ ์ปค์ง๊ธฐ ๋๋ฌธ์ ๋ ๊น๋ํ ์ฝ๋๋ฅผ ์ธ ์ ์๋ ๊ฒฝ์ฐ๊ฐ ๋ง์ต๋๋ค. ํ์ง๋ง ์ด๋ฌํ ์ญ์ ์ด ํญ์ ์ณ์ ๊ฒ์ ์๋๋๋ค. ๋ณต์กํ ๋ก์ง์ ์์๋ก ์ฎ๊ธฐ๋ฉด ์ด ์์ ์ปดํฌ๋ํธ๋ค์ ๋ ๋ํดํด์ง๊ธฐ ๋ง๋ จ์ด๊ณ ํ์ ์ปดํฌ๋ํธ๋ค์ ํ์ ์ด์์ผ๋ก ์ ์ฐํด์ ธ์ผ ํฉ๋๋ค.
์์์ผ๋ก ๋ ์ ์๋ ์ปดํฌ๋ํธ์ ์์ ์ ํ์ ์์ต๋๋ค. ์ฌ๋ฌ ์ปดํฌ๋ํธ, ํน์ ์ฌ๋ฌ ๊ฐ๋ก ๊ตฌ๋ถ๋ โ์ฌ๋กฏโ์ ๋๊ธฐ๋ ๋ฐฉ๋ฒ์ ๋ํด์๋ ์ฌ๊ธฐ๋ฅผ ์ฐธ์กฐํ์ธ์.
function Page(props) {
const user = props.user;
const content = <Feed user={user} />;
const topBar = (
<NavigationBar>
<Link href={user.permalink}>
<Avatar user={user} size={props.avatarSize} />
</Link>
</NavigationBar>
);
return (
<PageLayout
topBar={topBar}
content={content}
/>
);
}
์ด ํจํด์ ์ฌ์ฉํ๋ฉด ์์ ์ปดํฌ๋ํธ์ ์ง์ ๋ถ๋ชจ๋ฅผ ๋ถ๋ฆฌ(decouple)ํ๋ ๋ฌธ์ ๋ ๋๊ฐ ํด๊ฒฐํ ์ ์์ต๋๋ค. ๋ ๋์๊ฐ render props๋ฅผ ์ด์ฉํ๋ฉด ๋ ๋๋ง ๋๊ธฐ ์ ๋ถํฐ ์์ ์ปดํฌ๋ํธ๊ฐ ๋ถ๋ชจ ์ปดํฌ๋ํธ์ ์ํตํ๊ฒ ํ ์ ์์ต๋๋ค.
ํ์ง๋ง ๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ํธ๋ฆฌ ์ ์ฌ๋ฌ ๋ ๋ฒจ์ด ์๋ ๋ง์ ์ปดํฌ๋ํธ์ ์ฃผ์ด์ผ ํ ๋๋ ์์ต๋๋ค. ์ด๋ฐ ๋ฐ์ดํฐ ๊ฐ์ด ๋ณํ ๋๋ง๋ค ๋ชจ๋ ํ์ ์ปดํฌ๋ํธ์๊ฒ ๋๋ฆฌ โ๋ฐฉ์กโํ๋ ๊ฒ์ด context์ ๋๋ค. ํํ ์์๋ก ๋๋ ์ ํธ ๋ก์ผ์ผ, ํ ๋ง, ๋ฐ์ดํฐ ์บ์ ๋ฑ์ ๊ด๋ฆฌํ๋ ๋ฐ ์์ด์๋ ์ผ๋ฐ์ ์ผ๋ก context๋ฅผ ์ฌ์ฉํ๋ ๊ฒ ๊ฐ์ฅ ํธ๋ฆฌํฉ๋๋ค.
API
React.createContext
const MyContext = React.createContext(defaultValue);
Context ๊ฐ์ฒด๋ฅผ ๋ง๋ญ๋๋ค. Context ๊ฐ์ฒด๋ฅผ ๊ตฌ๋
ํ๊ณ ์๋ ์ปดํฌ๋ํธ๋ฅผ ๋ ๋๋งํ ๋ React๋ ํธ๋ฆฌ ์์์์ ๊ฐ์ฅ ๊ฐ๊น์ด ์๋ ์ง์ด ๋ง๋ Provider
๋ก๋ถํฐ ํ์ฌ๊ฐ์ ์ฝ์ต๋๋ค.
defaultValue
๋งค๊ฐ๋ณ์๋ ํธ๋ฆฌ ์์์ ์ ์ ํ Provider๋ฅผ ์ฐพ์ง ๋ชปํ์ ๋๋ง ์ฐ์ด๋ ๊ฐ์
๋๋ค. ์ด ๊ธฐ๋ณธ๊ฐ์ ์ปดํฌ๋ํธ๋ฅผ ๋
๋ฆฝ์ ์ผ๋ก ํ
์คํธํ ๋ ์ ์ฉํ ๊ฐ์
๋๋ค. Provider๋ฅผ ํตํด undefined
์ ๊ฐ์ผ๋ก ๋ณด๋ธ๋ค๊ณ ํด๋ ๊ตฌ๋
์ปดํฌ๋ํธ๋ค์ด defaultValue
๋ฅผ ์ฝ์ง๋ ์๋๋ค๋ ์ ์ ์ ์ํ์ธ์.
Context.Provider
<MyContext.Provider value={/* ์ด๋ค ๊ฐ */}>
Context ์ค๋ธ์ ํธ์ ํฌํจ๋ React ์ปดํฌ๋ํธ์ธ Provider๋ context๋ฅผ ๊ตฌ๋ ํ๋ ์ปดํฌ๋ํธ๋ค์๊ฒ context์ ๋ณํ๋ฅผ ์๋ฆฌ๋ ์ญํ ์ ํฉ๋๋ค.
Provider ์ปดํฌ๋ํธ๋ value
prop์ ๋ฐ์์ ์ด ๊ฐ์ ํ์์ ์๋ ์ปดํฌ๋ํธ์๊ฒ ์ ๋ฌํฉ๋๋ค. ๊ฐ์ ์ ๋ฌ๋ฐ์ ์ ์๋ ์ปดํฌ๋ํธ์ ์์ ์ ํ์ ์์ต๋๋ค. Provider ํ์์ ๋ ๋ค๋ฅธ Provider๋ฅผ ๋ฐฐ์นํ๋ ๊ฒ๋ ๊ฐ๋ฅํ๋ฉฐ, ์ด ๊ฒฝ์ฐ ํ์ Provider์ ๊ฐ์ด ์ฐ์ ์๋ฉ๋๋ค.
Provider ํ์์์ context๋ฅผ ๊ตฌ๋
ํ๋ ๋ชจ๋ ์ปดํฌ๋ํธ๋ Provider์ value
prop๊ฐ ๋ฐ๋ ๋๋ง๋ค ๋ค์ ๋ ๋๋ง ๋ฉ๋๋ค. Provider๋ก๋ถํฐ ํ์ consumer(.contextType
์ useContext
์ ํฌํจํ)๋ก์ ์ ํ๋ shouldComponentUpdate
๋ฉ์๋๊ฐ ์ ์ฉ๋์ง ์์ผ๋ฏ๋ก, ์์ ์ปดํฌ๋ํธ๊ฐ ์
๋ฐ์ดํธ๋ฅผ ๊ฑด๋ ๋ฐ๋๋ผ๋ consumer๊ฐ ์
๋ฐ์ดํธ๋ฉ๋๋ค.
context ๊ฐ์ ๋ฐ๋์๋์ง ์ฌ๋ถ๋ Object.is
์ ๋์ผํ ์๊ณ ๋ฆฌ์ฆ์ ์ฌ์ฉํด ์ด์ ๊ฐ๊ณผ ์๋ก์ด ๊ฐ์ ๋น๊ตํด ์ธก์ ๋ฉ๋๋ค.
์ฃผ์
์์ ๊ฐ์ ๋ฐฉ์์ผ๋ก ๋ณํ๋ฅผ ์ธก์ ํ๊ธฐ ๋๋ฌธ์ ๊ฐ์ฒด๋ฅผ
value
๋ก ๋ณด๋ด๋ ๊ฒฝ์ฐ ๋ค์ ๋ฌธ์ ๊ฐ ์๊ธธ ์ ์์ต๋๋ค. ์ฃผ์์ฌํญ์ ์ฐธ์กฐํ์ธ์.
Class.contextType
class MyClass extends React.Component {
componentDidMount() {
let value = this.context;
/* MyContext์ ๊ฐ์ ์ด์ฉํ ์ฝ๋ */
}
componentDidUpdate() {
let value = this.context;
/* ... */
}
componentWillUnmount() {
let value = this.context;
/* ... */
}
render() {
let value = this.context;
/* ... */
}
}
MyClass.contextType = MyContext;
React.createContext()
๋ก ์์ฑํ Context ๊ฐ์ฒด๋ฅผ ์ํ๋ ํด๋์ค์ contextType
ํ๋กํผํฐ๋ก ์ง์ ํ ์ ์์ต๋๋ค. ์ด ํ๋กํผํฐ๋ฅผ ํ์ฉํด ํด๋์ค ์์์ this.context
๋ฅผ ์ด์ฉํด ํด๋น Context์ ๊ฐ์ฅ ๊ฐ๊น์ด Provider๋ฅผ ์ฐพ์ ๊ทธ ๊ฐ์ ์ฝ์ ์ ์๊ฒ๋ฉ๋๋ค. ์ด ๊ฐ์ render๋ฅผ ํฌํจํ ๋ชจ๋ ์ปดํฌ๋ํธ ์๋ช
์ฃผ๊ธฐ ๋งค์๋์์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
์ฃผ์
์ด API๋ฅผ ์ฌ์ฉํ๋ฉด ํ๋์ context๋ง ๊ตฌ๋ ํ ์ ์์ต๋๋ค. ์ฌ๋ฌ context๋ฅผ ๊ตฌ๋ ํ๊ธฐ ์ํด์๋ ์ฌ๋ฌ context ๊ตฌ๋ ํ๊ธฐ๋ฅผ ์ฐธ์กฐํ์ธ์.
์คํ์ ๊ธฐ๋ฅ์ธ public class fields syntax๋ฅผ ์ฌ์ฉํ๊ณ ์๋ค๋ฉด ์ ์ ํด๋์ค ํ๋กํผํฐ๋ก
contextType
์ ์ง์ ํ ์ ์์ต๋๋ค.
class MyClass extends React.Component {
static contextType = MyContext;
render() {
let value = this.context;
/* context ๊ฐ์ ์ด์ฉํ ๋ ๋๋ง */
}
}
Context.Consumer
<MyContext.Consumer>
{value => /* context ๊ฐ์ ์ด์ฉํ ๋ ๋๋ง */}
</MyContext.Consumer>
context ๋ณํ๋ฅผ ๊ตฌ๋ ํ๋ React ์ปดํฌ๋ํธ์ ๋๋ค. ์ด ์ปดํฌ๋ํธ๋ฅผ ์ฌ์ฉํ๋ฉด ํจ์ ์ปดํฌ๋ํธ์์์ context๋ฅผ ๊ตฌ๋ ํ ์ ์์ต๋๋ค.
Context.Consumer์ ์์์ ํจ์์ฌ์ผํฉ๋๋ค. ์ด ํจ์๋ context์ ํ์ฌ๊ฐ์ ๋ฐ๊ณ React ๋
ธ๋๋ฅผ ๋ฐํํฉ๋๋ค. ์ด ํจ์๊ฐ ๋ฐ๋ value
๋งค๊ฐ๋ณ์ ๊ฐ์ ํด๋น context์ Provider ์ค ์์ ํธ๋ฆฌ์์ ๊ฐ์ฅ ๊ฐ๊น์ด Provider์ value
prop๊ณผ ๋์ผํฉ๋๋ค. ์์์ Provider๊ฐ ์๋ค๋ฉด value
๋งค๊ฐ๋ณ์ ๊ฐ์ createContext()
์ ๋ณด๋๋ defaultValue
์ ๋์ผํ ๊ฒ์
๋๋ค.
์ฃผ์
ํจ์๋ฅผ ์์์ผ๋ก ๋ฐ๋ ํจํด์ ๋ํด์๋ render props์ ์ฐธ์กฐํ์ธ์.
Context.displayName
Context ๊ฐ์ฒด๋ displayName
๋ฌธ์์ด ์์ฑ์ ์ค์ ํ ์ ์์ต๋๋ค. React ๊ฐ๋ฐ์ ๋๊ตฌ๋ ์ด ๋ฌธ์์ด์ ์ฌ์ฉํด์ context๋ฅผ ์ด๋ป๊ฒ ๋ณด์ฌ์ค ์ง ๊ฒฐ์ ํฉ๋๋ค.
์๋ฅผ ๋ค์ด, ์๋ ์ปดํฌ๋ํธ๋ ๊ฐ๋ฐ์ ๋๊ตฌ์ MyDisplayName๋ก ํ์๋ฉ๋๋ค.
const MyContext = React.createContext(/* some value */);
MyContext.displayName = 'MyDisplayName';
<MyContext.Provider> // "MyDisplayName.Provider" in DevTools
<MyContext.Consumer> // "MyDisplayName.Consumer" in DevTools
์์
๊ฐ์ด ๋ณํ๋ context
theme ๊ฐ์ด ๋ณํ๋ ์ข ๋ ๋ณต์กํ ์์์ ๋๋ค.
theme-context.js
export const themes = {
light: {
foreground: '#000000',
background: '#eeeeee',
},
dark: {
foreground: '#ffffff',
background: '#222222',
},
};
export const ThemeContext = React.createContext( themes.dark // ๊ธฐ๋ณธ๊ฐ);
themed-button.js
import {ThemeContext} from './theme-context';
class ThemedButton extends React.Component {
render() {
let props = this.props;
let theme = this.context; return (
<button
{...props}
style={{backgroundColor: theme.background}}
/>
);
}
}
ThemedButton.contextType = ThemeContext;
export default ThemedButton;
app.js
import {ThemeContext, themes} from './theme-context';
import ThemedButton from './themed-button';
// ThemedButton๋ฅผ ์ฌ์ฉํ๋ ์ค๊ฐ์ ์๋ ์ปดํฌ๋ํธ
function Toolbar(props) {
return (
<ThemedButton onClick={props.changeTheme}>
Change Theme
</ThemedButton>
);
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
theme: themes.light,
};
this.toggleTheme = () => {
this.setState(state => ({
theme:
state.theme === themes.dark
? themes.light
: themes.dark,
}));
};
}
render() {
// ThemeProvider ์์ ์๋ ThemedButton์ state๋ก๋ถํฐ theme ๊ฐ์ ์ฝ์ง๋ง // Provider ๋ฐ์ ์๋ ThemedButton๋ ๊ธฐ๋ณธ๊ฐ์ธ dark๋ฅผ ์ฌ์ฉํฉ๋๋ค. return (
<Page>
<ThemeContext.Provider value={this.state.theme}> <Toolbar changeTheme={this.toggleTheme} /> </ThemeContext.Provider> <Section>
<ThemedButton /> </Section>
</Page>
);
}
}
ReactDOM.render(<App />, document.root);
ํ์ ์ปดํฌ๋ํธ์์ context ์ ๋ฐ์ดํธํ๊ธฐ
์ปดํฌ๋ํธ ํธ๋ฆฌ ํ์ ๊น์์ด ์๋ ์ปดํฌ๋ํธ์์ context๋ฅผ ์ ๋ฐ์ดํธ ํด์ผ ํ ๋๊ฐ ์ข ์ข ์์ต๋๋ค. ๊ทธ๋ด ๋๋ context๋ฅผ ํตํด ๋งค์๋๋ฅผ ๋ณด๋ด๋ฉด ๋ฉ๋๋ค.
theme-context.js
// createContext์ ๋ณด๋ด๋ ๊ธฐ๋ณธ๊ฐ์ ๋ชจ์์
// ํ์ ์ปดํฌ๋ํธ๊ฐ ๋ฐ๊ณ ์๋ ๋งค๊ฐ๋ณ์ ๋ชจ์๊ณผ ๋์ผํ๊ฒ ๋ง๋๋ ๊ฒ ์์ง๋ง์ธ์!
export const ThemeContext = React.createContext({
theme: themes.dark, toggleTheme: () => {},});
theme-toggler-button.js
import {ThemeContext} from './theme-context';
function ThemeTogglerButton() {
// ThemeTogglerButton๋ context๋ก๋ถํฐ // theme ๊ฐ๊ณผ ํจ๊ป toggleTheme ๋งค์๋๋ ๋ฐ๊ณ ์์ต๋๋ค. return (
<ThemeContext.Consumer>
{({theme, toggleTheme}) => ( <button
onClick={toggleTheme}
style={{backgroundColor: theme.background}}>
Toggle Theme
</button>
)}
</ThemeContext.Consumer>
);
}
export default ThemeTogglerButton;
app.js
import {ThemeContext, themes} from './theme-context';
import ThemeTogglerButton from './theme-toggler-button';
class App extends React.Component {
constructor(props) {
super(props);
this.toggleTheme = () => {
this.setState(state => ({
theme:
state.theme === themes.dark
? themes.light
: themes.dark,
}));
};
// state์ ์
๋ฐ์ดํธ ๋ฉ์๋๋ ํฌํจ๋์ด์์ผ๋ฏ๋ก // ์ด ๋ํ context Provider๋ฅผ ํตํด ์ ๋ฌ๋ ๊ฒ์
๋๋ค. this.state = {
theme: themes.light,
toggleTheme: this.toggleTheme, };
}
render() {
// Provider์ state ์ ์ฒด๋ฅผ ๋๊ฒจ์ค๋๋ค. return (
<ThemeContext.Provider value={this.state}> <Content />
</ThemeContext.Provider>
);
}
}
function Content() {
return (
<div>
<ThemeTogglerButton />
</div>
);
}
ReactDOM.render(<App />, document.root);
์ฌ๋ฌ context ๊ตฌ๋ ํ๊ธฐ
๊ฐ context๋ง๋ค Consumer๋ฅผ ๊ฐ๋ณ ๋ ธ๋๋ก ๋ง๋ค๊ฒ ์ค๊ณ๋์ด์๋๋ฐ, ์ด๊ฒ์ context ๋ณํ๋ก ์ธํด ๋ค์ ๋ ๋๋งํ๋ ๊ณผ์ ์ ๋น ๋ฅด๊ฒ ์ ์งํ๊ธฐ ์ํจ์ ๋๋ค.
// ๊ธฐ๋ณธ๊ฐ์ด light์ธ ThemeContext
const ThemeContext = React.createContext('light');
// ๋ก๊ทธ์ธํ ์ ์ ์ ๋ณด๋ฅผ ๋ด๋ UserContext
const UserContext = React.createContext({
name: 'Guest',
});
class App extends React.Component {
render() {
const {signedInUser, theme} = this.props;
// context ์ด๊ธฐ๊ฐ์ ์ ๊ณตํ๋ App ์ปดํฌ๋ํธ
return (
<ThemeContext.Provider value={theme}> <UserContext.Provider value={signedInUser}> <Layout />
</UserContext.Provider> </ThemeContext.Provider> );
}
}
function Layout() {
return (
<div>
<Sidebar />
<Content />
</div>
);
}
// ์ฌ๋ฌ context์ ๊ฐ์ ๋ฐ๋ ์ปดํฌ๋ํธ
function Content() {
return (
<ThemeContext.Consumer> {theme => ( <UserContext.Consumer> {user => ( <ProfilePage user={user} theme={theme} /> )} </UserContext.Consumer> )} </ThemeContext.Consumer> );
}
๋ ์ด์์ context ๊ฐ์ด ํจ๊ป ์ฐ์ด๋ ๊ฒฝ์ฐ๊ฐ ๋ง๋ค๋ฉด ๊ทธ ๊ฐ๋ค์ ํ ๋ฒ์ ๋ฐ๋ render prop ์ปดํฌ๋ํธ๋ฅผ ๋ง๋๋ ๊ฒ์ ๊ณ ๋ คํด๋ณด์ธ์.
์ฃผ์์ฌํญ
๋ค์ ๋ ๋๋งํ ์ง ์ฌ๋ถ๋ฅผ ์ ํ ๋ ์ฐธ์กฐ(reference)๋ฅผ ํ์ธํ๊ธฐ ๋๋ฌธ์, Provider์ ๋ถ๋ชจ๊ฐ ๋ ๋๋ง ๋ ๋๋ง๋ค ๋ถํ์ํ๊ฒ ํ์ ์ปดํฌ๋ํธ๊ฐ ๋ค์ ๋ ๋๋ง ๋๋ ๋ฌธ์ ๊ฐ ์๊ธธ ์๋ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด ์๋ ์ฝ๋๋ value
๊ฐ ๋ฐ๋ ๋๋ง๋ค ๋งค๋ฒ ์๋ก์ด ๊ฐ์ฒด๊ฐ ์์ฑ๋๋ฏ๋ก Provider๊ฐ ๋ ๋๋ง ๋ ๋๋ง๋ค ๊ทธ ํ์์์ ๊ตฌ๋
ํ๊ณ ์๋ ์ปดํฌ๋ํธ ๋ชจ๋๊ฐ ๋ค์ ๋ ๋๋ง ๋ ๊ฒ์
๋๋ค.
class App extends React.Component {
render() {
return (
<MyContext.Provider value={{something: 'something'}}> <Toolbar />
</MyContext.Provider>
);
}
}
์ด๋ฅผ ํผํ๊ธฐ ์ํด์๋ ๊ฐ์ ๋ถ๋ชจ์ state๋ก ๋์ด์ฌ๋ฆฌ์ธ์.
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
value: {something: 'something'}, };
}
render() {
return (
<MyContext.Provider value={this.state.value}> <Toolbar />
</MyContext.Provider>
);
}
}
์์ API
์ฃผ์
์ด์ ๋ฒ์ ์ React์ ์คํ์ ์ธ ๋จ๊ณ์ context API๊ฐ ์กด์ฌํ ์ ์ด ์์ต๋๋ค. ์์ API๋ ๋ชจ๋ 16.x ๋ฒ์ ์์ ์ง์๋ ์์ ์ด์ง๋ง ์๋ก์ด API๋ก ์ฎ๊ธธ ๊ฒ์ ๊ถ์ฅํฉ๋๋ค. ๋ค์ ๋ฉ์ด์ ๋ฐฐํฌ์์ ์์ API๋ ์ญ์ ๋ ๊ฒ์ ๋๋ค. ์์ API ๋ฌธ์๋ ์ฌ๊ธฐ์ ์์ต๋๋ค.