ContextAPI ์•Œ์•„๋ณด๊ธฐ

junameeยท2021๋…„ 9์›” 13์ผ
2

ํ”„๋ก ํŠธ์—”๋“œ

๋ชฉ๋ก ๋ณด๊ธฐ
8/16

๐Ÿ“˜ React๊ณต์‹๋ฌธ์„œ ์ฐธ๊ณ 

context๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์ „์— ๊ณ ๋ คํ•  ๊ฒƒ

  • context์˜ ์ฃผ ์šฉ๋„: ๋‹ค์–‘ํ•œ ๋ ˆ๋ฒจ์˜ ์ค‘์ฒฉ๋œ ๋งŽ์€ ์ปดํฌ๋„ŒํŠธ์— ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•˜๊ธฐ ์œ„ํ•จ
  • ์ฃผ์˜ํ•  ์  : ์žฌ์‚ฌ์šฉ์ด ์–ด๋ ค์›Œ์ง€๋ฏ€๋กœ ๊ผญ ํ•„์š”ํ•  ๋•Œ๋งŒ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

๋งŒ์•ฝ, prop์„ ๋„˜๊ธฐ๋Š” ๊ฒƒ์„ ์ค„์ด๊ณ  ์‹ถ์€ ์ด์œ ๋ผ๋ฉด Component Composition (์ปดํฌ๋„ŒํŠธ ํ•ฉ์„ฑ์˜ ๋ฐฉ๋ฒ•๋„ ์žˆ๋‹ค) ๋ฐฉ๋ฒ•๋„ ์žˆ๋‹ค. prop ๋Œ€์‹ ์— ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ์—ฌ๋Ÿฌ๊ฐœ์˜ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋„˜๊ธธ ์ˆ˜ ์žˆ๋‹ค.

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}
    />
  );
}

๋‹จ์ˆœํ•œ ์ „๋‹ฌ์ด ์•„๋‹Œ,
๋™์ผํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์—ฌ๋Ÿฌ ๋ ˆ๋ฒจ์˜ ์ปดํฌ๋„ŒํŠธ์— ์•Œ๋ ค์•ผํ•  ํ•„์š”๊ฐ€ ์žˆ์„ ๋• context๋ฅผ ์“ฐ๋Š” ๊ฒƒ์ด ์ข‹๋‹ค. ์˜ˆ๋ฅผ ๋“ค๋ฉด ๋กœ๊ทธ์ธ ์ •๋ณด, ํ…Œ๋งˆ, ๋ฐ์ดํ„ฐ ์บ์‹œ ๋“ฑ์„ ๊ด€๋ฆฌํ•  ๋•Œ ์ด๋‹ค.


API

React.createContext

const MyContext = React.createContext(defaultValue)
์ „์—ญ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ด์„ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.
defaultValue๋Š” ์ ์ ˆํ•œ Provider ์ง์„ ์ฐพ์ง€ ๋ชปํ•  ๋•Œ ์‚ฌ์šฉ๋˜๋Š” value

Context.Provider

<MyContext.Provider value={//์ „๋‹ฌํ•˜๋Š” ๋ฐ์ดํ„ฐ}>
Provider๋Š” context๋ฅผ ๊ตฌ๋…ํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ(consumer)์— context์˜ ๋ณ€ํ™”๋ฅผ ์•Œ๋ฆฌ๋Š” ์—ญํ• ์„ ํ•œ๋‹ค. value๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค Providerํ•˜์œ„์—์„œ context๋ฅผ ๊ตฌ๋…ํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ๋“ค์„ ๋‹ค์‹œ ๋ Œ๋”๋ง ์‹œํ‚จ๋‹ค.

Context.Consumer

<MyContext.Consumer>
  {value=><div>name: {value}</div>}
</MyContext.Consumer>

context์˜ ๋ณ€ํ™”๋ฅผ ๊ตฌ๋…ํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ์ด๋ฉฐ context์˜ ๊ฐ’์„ ๋ฐ›์•„ React Node๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. value ๋งค๊ฐœ๋ณ€์ˆ˜๋Š” Provider ์ค‘ ์ƒ์œ„ํŠธ๋ฆฌ์—์„œ ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด Provider์˜ prop๊ณผ ๋™์ผํ•˜๋‹ค. ๋งŒ์ผ, ์ƒ์œ„์— Provider๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š๋‹ค๋ฉด context๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•  ๋•Œ ์ง€์ •ํ•œ defaultValue์™€ ๋™์ผํ•  ๊ฒƒ์ด๋‹ค.

Provider์™€ 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>
  );
}

ContextAPI์™€ ์ตœ์ ํ™”

Consumer๋กœ ๊ฐ์‹ธ๋ฒ„๋ฆฐ ๊ณต๊ฐ„ ๋‚ด์—์„œ๋Š” value๋ฅผ ๋ชจ๋‘ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, ๋‹จ์ ์œผ๋กœ๋Š” ์ „์—ญ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ์ปดํฌ๋„ŒํŠธ์—์„œ๋„ ๋ Œ๋”๋ง์ด ๋ฐœ์ƒํ•œ๋‹ค.
๋•Œ๋ฌธ์— Consumer๋กœ๋Š” ์ •๋ง ๋ฐ์ดํ„ฐ๋ฅผ ํ•„์š”๋กœ ํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ๋งŒ ๊ฐ์‹ธ๋„๋ก ํ•ด์•ผํ•œ๋‹ค.

๋˜ํ•œ, Provider์—์„œ ์ „์—ญ์ƒํƒœ๋กœ ๋„˜๊ธธ prop์„ ์ง์ ‘ ์„ ์–ธํ•ด ์ƒˆ ๊ฐ์ฒด๋กœ ์ธ์‹ํ•˜์ง€ ์•Š๋„๋ก ํ•ด์•ผํ•œ๋‹ค. ์ƒˆ๋กœ์šด ๊ฐ์ฒด๋กœ ์ธ์‹ํ•˜๋ฉด Provider๊ฐ€ ๋ Œ๋”๋ง ๋  ๋•Œ ํ•˜์œ„์˜ ๊ตฌ๋…ํ•˜๋Š” ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ๋“ค์ด ๋ Œ๋”๋ง๋˜๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

class App extends React.Component {
  render() {
    return (
      <MyContext.Provider value={{something: 'something'}}>
        <Toolbar />
      </MyContext.Provider>
    );
  }
}

{{something: 'something'}}์ƒˆ๋กœ์šด ๊ฐ์ฒด๋กœ ๋ณด๊ณ  Toolbar๋ฅผ ํ•ญ์ƒ ๋ Œ๋”๋ง ์‹œํ‚ค๊ฒŒ ๋œ๋‹ค. ์ด๋ฅผ ๋ง‰๊ธฐ ์œ„ํ•ด ๊ฐ์ฒด์˜ ๊ฐ’์„ ๋ถ€๋ชจ์˜ state๋กœ ๋Œ์–ด์˜ฌ๋ ค ๊ด€๋ฆฌํ•ด์•ผํ•œ๋‹ค.

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: {something: 'something'}, //state์— ์„ ์–ธ!
    };
  }

  render() {
    return (
      <MyContext.Provider value={this.state.value}>
        <Toolbar />
      </MyContext.Provider>
    );
  }
}

Hook์„ ์‚ฌ์šฉํ•œ useContext

Consumer๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์ด๋‹ค. ์ปดํฌ๋„ŒํŠธ๋“ค์„ ๊ฐ์Œ€ ํ•„์š”์—†์ด,
์ „์—ญ์ƒํƒœ๋ฅผ ์‚ฌ์šฉํ•  ๊ณณ์—์„œ const globalState = useContext(SampleContext)์™€ ๊ฐ™์ด ์„ ์–ธํ•˜๋ฉด globalState๊ฐ€ ํ•ด๋‹น ํ›…์ด ์„ ์–ธ๋œ ์ปดํฌ๋„ŒํŠธ์—์„œ ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด Provider์˜ ์ƒํƒœ๊ฐ’์„ ๊ฐ–๊ฒŒ ๋œ๋‹ค.

์ด ๋•Œ, context๊ฐ’์ด ๋ณ€๊ฒฝ๋˜๋ฉด useContext๋Š” Consumer์™€ ๋™์ผํ•˜๊ฒŒ ํ˜ธ์ถœํ•œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ฆฌ๋ Œ๋”๋ง ์‹œํ‚จ๋‹ค.

useReducer

useState์ฒ˜๋Ÿผ ์ƒํƒœ๋งŒ์„ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š๊ณ  ์ด์ „ state์— ์˜์กดํ•˜์—ฌ ์—ฌ๋Ÿฌ ์กฐ๊ฑด์— ๋Œ€ํ•ด ์ƒˆ๋กœ์šด state๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒฝ์šฐ ์œ ์šฉํ•˜๋‹ค. ์ฝœ๋ฐฑ ๋Œ€์‹ ์— dispatch๋ฅผ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ƒํƒœ์—…๋ฐ์ดํŠธ๋ฅผ ์‹œํ‚ค๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ตœ์ ํ™”ํ•  ์ˆ˜ ์žˆ๋‹ค.
(dispatch๋Š” ๋‹ค์‹œ ๋ Œ๋”๋ง์„ ์‹œํ‚ค์ง€ ์•Š๋Š”๋‹ค.)

profile
์•„ํ‹ฐํด๋ฆฌ์ŠคํŠธ - bit.ly/3wjIlZJ

0๊ฐœ์˜ ๋Œ“๊ธ€