We want to hear from you!Take our 2021 Community Survey!
Support Ukraine ๐Ÿ‡บ๐Ÿ‡ฆ Help Provide Humanitarian Aid to Ukraine.

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 ๋ฌธ์„œ๋Š” ์—ฌ๊ธฐ์— ์žˆ์Šต๋‹ˆ๋‹ค.

Is this page useful?Edit this page