๐ŸŽจ Context API

Lee Jooamยท2022๋…„ 6์›” 1์ผ
0

Props Drilling

export const First = () => {
  const [num, setNum] = useState(0);

  return (
    <>
      <span>{num}</span>
      <Second num={num} />
    </>
  );
};
const Second = (props) => {
  return <Third num={props.num} />;
};
const Third = (props) => {
  return <Fourth num={props.num} />;
};
const Fourth = (props) => {
  return <span>{props.num}</span>;
};

๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ฝ”๋“œ๊ฐ€ ์žˆ๋‹ค. ์กฐ๊ธˆ ์ด์ƒํ•˜์ง€๋งŒ ์ƒ์ƒ๋ ฅ์„ ๋ฐœํœ˜ํ•ด์„œ ์‚ด์„ ๋ถ™์—ฌ๋ณด์ž. num์€ First์—์„œ ๊ด€๋ฆฌํ•˜๊ณ , First์™€ Fourth์—์„œ ์‚ฌ์šฉํ•œ๋‹ค.

ํ•˜์ง€๋งŒ ์“ธ๋ฐ์—†์ด num์„ Second, Third์—๋„ ์ „๋‹ฌํ•ด์•ผํ•œ๋‹ค. ์ปดํฌ๋„ŒํŠธ ๊ณ„์ธต์ด ๊ทธ๋ ‡๊ฒŒ ๋˜์–ด์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ด๋Ÿฌํ•œ ํ˜„์ƒ์ด props drilling์ด๋‹ค.

์˜ค์ง ์ „๋‹ฌ๋งŒ์„ ์œ„ํ•œ props๋“ค์ด ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ๋“ค์— ๋‹ค์ˆ˜ ์กด์žฌํ•œ๋‹ค๋ฉด ์•ฑ์˜ ๊ทœ๋ชจ๊ฐ€ ์ปค์งˆ์ˆ˜๋ก ์ข‹์ง€ ์•Š์€ ์˜ํ–ฅ๋„ ์ปค์งˆ ๊ฒƒ์ด๋‹ค.

Component Composition

์ปดํฌ๋„ŒํŠธ ํ•ฉ์„ฑ์„ ํ†ตํ•ด props drilling์„ ํ•ด๊ฒฐํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ์œ„์˜ ์ฝ”๋“œ๋ฅผ ์ปดํฌ๋„ŒํŠธ ํ•ฉ์„ฑ์œผ๋กœ ํ•ด๊ฒฐํ•œ ํ˜•ํƒœ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

export const First = () => {
  const [num, setNum] = useState(0);

  return (
    <>
      <span>{num}</span>
      <Second>
        <Third>
          <Fourth num={num} />
        </Third>
      </Second>
    </>
  );
};
const Second = (props) => {
  return <>{props.children}</>;
};
const Third = (props) => {
  return <>{props.children}</>;
};
const Fourth = (props) => {
  return <span>{props.num}</span>;
};

์ „๋‹ฌ๋งŒ์„ ์œ„ํ•œ props๋Š” ๋”์ด์ƒ ์—†๊ณ  ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ์—์„œ ๋ฐ”๋กœ ํ•„์š”ํ•œ ์†์„ฑ์„ ์ฃผ์ž…์‹œ์ผœ์คฌ๋‹ค.

์ปดํฌ๋„ŒํŠธ ํ•ฉ์„ฑ์œผ๋กœ๋งŒ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ๊ตณ์ด Context๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค.

ํ•˜์ง€๋งŒ ๋กœ๊ทธ์ธ ์—ฌ๋ถ€, ํ˜„์žฌ ํ…Œ๋งˆ ๋“ฑ ํ•˜๋‚˜์˜ ์ปดํฌ๋„ŒํŠธ ํŠธ๋ฆฌ๊ฐ€ ์•„๋‹Œ ๋‹ค์–‘ํ•œ ๊ณณ์—์„œ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด context๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒŒ ๋” ์ง๊ด€์ ์œผ๋กœ ์ฝ”๋“œ๊ฐ€ ๋ณด์ผ ์ˆ˜ ์žˆ๋‹ค.

Context

const myContext = createContext();

const MyStore = (props) => {
  const [info, setInfo] = useState({
    name: "lee",
    age: 27,
  });

  return (
    <myContext.Provider
      value={{
        info,
        onClick: () => {
          setInfo((prev) => ({ ...prev, age: prev.age++ }));
        },
      }}
    >
      {props.children}
    </myContext.Provider>
  );
};

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

const ContextConsumer = () => {
  const context = useContext(myContext);
  useEffect(() => {
    console.log("ContextConsumer is rendered!");
  });

  return (
    <div>
      <h1>Hello my name is {context.info.name}</h1>
      <h1>I'am {context.info.age} years old.</h1>
      <button onClick={context.onClick}>Click Me!</button>
    </div>
  );
};

const ContextInner = () => {
  useEffect(() => {
    console.log("ContextInner is rendered!");
  });

  return (
    <>
      <span>inner</span>
      <ContextConsumer />
    </>
  );
};

const ContextExample = () => {
  return (
    <MyStore>
      <ContextInner />
    </MyStore>
  );
};

context๋ฅผ ์†Œ๋น„ํ•˜๋Š” ๊ฑด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค. MyStore์— children์œผ๋กœ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋„˜๊ฒจ์ฃผ๊ณ  ํ•„์š”ํ•œ ์ปดํฌ๋„ŒํŠธ์—์„œ useContext ํ›…์„ ์ด์šฉํ•ด context๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

์ด๋•Œ ๋ฆฌ๋ Œ๋”๋ง ๋ถ€๋ถ„์„ ์ฃผ์˜ํ•ด์„œ ๋ด์•ผํ•˜๋Š”๋ฐ, ๋ฒ„ํŠผ์„ ํด๋ฆญํ•ด context๋ฅผ ๋ฐ”๊ฟ” MyStore๊ฐ€ ๋ฆฌ๋ Œ๋”๋ง์ด ๋ฐœ์ƒํ–ˆ์ง€๋งŒ ContextInner ์ปดํฌ๋„ŒํŠธ๋Š” ๋ฆฌ๋ Œ๋”๋ง์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋‹ค.

Provider ํ•˜์œ„์—์„œ context๋ฅผ ๊ตฌ๋…ํ•˜๋Š” ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ๋Š” Provider์˜ value prop๊ฐ€ ๋ฐ”๋€” ๋•Œ๋งˆ๋‹ค ๋‹ค์‹œ ๋ Œ๋”๋ง ๋ฉ๋‹ˆ๋‹ค. Provider๋กœ๋ถ€ํ„ฐ ํ•˜์œ„ consumer(.contextType์™€ useContext์„ ํฌํ•จํ•œ)๋กœ์˜ ์ „ํŒŒ๋Š” shouldComponentUpdate ๋ฉ”์„œ๋“œ๊ฐ€ ์ ์šฉ๋˜์ง€ ์•Š์œผ๋ฏ€๋กœ, ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์—…๋ฐ์ดํŠธ๋ฅผ ๊ฑด๋„ˆ ๋›ฐ๋”๋ผ๋„ consumer๊ฐ€ ์—…๋ฐ์ดํŠธ๋ฉ๋‹ˆ๋‹ค.

๋ฆฌ์•กํŠธ ๊ณต์‹๋ฌธ์„œ์— ์จ์žˆ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ context๋ฅผ ๊ตฌ๋…ํ•˜๋Š” ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ๋Š” value๊ฐ€ ๋ฐ”๋€” ๋•Œ๋งˆ๋‹ค ๋ฆฌ๋ Œ๋”๋ง์ด ๋ฐœ์ƒํ•œ๋‹ค.

Context๊ฐ€ ์ •๋‹ต์ผ๊นŒ?

const yourContext = createContext();

const YourStore = (props) => {
  const [job, setJob] = useState("unemployed");

  return (
    <yourContext.Provider value={job}>{props.children}</yourContext.Provider>
  );
};

๋‹ค์Œ๊ณผ ๊ฐ™์€ context๋ฅผ ํ•˜๋‚˜ ์ถ”๊ฐ€ํ•œ๋‹ค๊ณ  ํ•ด๋ณด์ž. ์ด๊ฒƒ์„ Provider๋กœ ์ œ๊ณตํ•˜๋ ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ํ•ด์•ผํ•œ๋‹ค.

const ContextExample = () => {
  return (
    <YourStore>
      <MyStore>
        <ContextInner />
      </MyStore>
    </YourStore>
  );
};

context๊ฐ€ ์ถ”๊ฐ€๋ ์ˆ˜๋ก ์ฝ”๋“œ๋Š” ์ ์  ๋ณด๊ธฐ ํž˜๋“ค์–ด์งˆ ๊ฒƒ์ด๋‹ค. ๋ฌผ๋ก  ์กฐ๊ธˆ ๋ณด๊ธฐ ์ข‹๊ฒŒ ๋งŒ๋“œ๋Š” ๊ธฐ๋ฒ•๋„ ์กด์žฌํ•˜์ง€๋ฉด ์ด ๊ธ€์—์„œ๋Š” ๋‹ค๋ฃจ์ง€ ์•Š๊ฒ ๋‹ค. ๊ด€์‹ฌ์ด ์žˆ๋‹ค๋ฉด React context hell์„ ๋ณด๊ธธ ๋ฐ”๋ž€๋‹ค.

์ด๊ฒƒ ๋ง๊ณ ๋„ ๋ฌธ์ œ๊ฐ€ ๋˜ ์žˆ๋‹ค.

const ContextExample = () => {
  return (
    <>
      <YourStore>
        <MyStore>
          <ContextInner />
        </MyStore>
      </YourStore>
      <ContextConsumer />
    </>
  );
};

๋งŒ์•ฝ ContextConsumer์„ ๋‹ค๋ฅธ ๊ณณ์—์„œ ์žฌ์‚ฌ์šฉํ•˜๋ ค๋ฉด ์—๋Ÿฌ๋ฅผ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค. context์˜ ์‚ฌ์šฉ์€ ์žฌ์‚ฌ์šฉ์„ฑ์„ ๋–จ์–ด๋œจ๋ฆฐ๋‹ค๋Š” ๋‹จ์ ๋„ ์žˆ๋‹ค.

๋ชจ๋“  ๋„๊ตฌ๊ฐ€ ๊ทธ๋Ÿฐ ๊ฒƒ์ฒ˜๋Ÿผ ํ•ญ์ƒ ์ƒํ™ฉ์— ๋งž๋Š” ๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒŒ ์ข‹๋‹ค.

profile
ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์ž๋กœ ๊ฑธ์–ด๊ฐ€๋Š” ์ค‘์ž…๋‹ˆ๋‹ค.

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