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 ๋ฌธ์๋ ์ฌ๊ธฐ์ ์์ต๋๋ค.