[React - TIL] context API ๋ž€?

Leesuยท2023๋…„ 3์›” 21์ผ
0
post-thumbnail

๐ŸŸก context api๋ž€?

context๋ฅผ ์ด์šฉํ•˜๋ฉด ๋‹จ๊ณ„๋งˆ๋‹ค ์ผ์ผ์ด props๋ฅผ ๋„˜๊ฒจ์ฃผ์ง€ ์•Š๊ณ ๋„ ์ปดํฌ๋„ŒํŠธ ํŠธ๋ฆฌ ์ „์ฒด์— ๋ฐ์ดํ„ฐ๋ฅผ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ผ๋ฐ˜์ ์ธ React ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ๋ฐ์ดํ„ฐ๋Š” ์œ„์—์„œ ์•„๋ž˜๋กœ (์ฆ‰, ๋ถ€๋ชจ๋กœ๋ถ€ํ„ฐ ์ž์‹์—๊ฒŒ) props๋ฅผ ํ†ตํ•ด ์ „๋‹ฌ๋˜์ง€๋งŒ, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์•ˆ์˜ ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ๋“ค์— ์ „ํ•ด์ค˜์•ผ ํ•˜๋Š” props์˜ ๊ฒฝ์šฐ (์˜ˆ๋ฅผ ๋“ค๋ฉด ์„ ํ˜ธ ๋กœ์ผ€์ผ, UI ํ…Œ๋งˆ) ์ด ๊ณผ์ •์ด ๋ฒˆ๊ฑฐ๋กœ์šธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. context๋ฅผ ์ด์šฉํ•˜๋ฉด, ํŠธ๋ฆฌ ๋‹จ๊ณ„๋งˆ๋‹ค ๋ช…์‹œ์ ์œผ๋กœ props๋ฅผ ๋„˜๊ฒจ์ฃผ์ง€ ์•Š์•„๋„ ๋งŽ์€ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ด๋Ÿฌํ•œ ๊ฐ’์„ ๊ณต์œ ํ•˜๋„๋ก ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.(์ „์—ญ์  ์‚ฌ์šฉ)

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

๐ŸŸก ์–ธ์ œ? ์™œ ์‚ฌ์šฉํ• ๊นŒ?

  • React์—์„œ props drilling์„ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•œ ๋ฐฉ๋ฒ• ์ค‘ ํ•˜๋‚˜๋กœ ์ž์ฃผ ์‚ฌ์šฉํ•œ๋‹ค.
  • ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์—์„œ ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, createContext()๋ฅผ ํ†ตํ•ด Provider์™€ Consumer๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ์ „์—ญ์ ์œผ๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.
    Provider ๋กœ ๊ฐ์‹ธ์ง„ ์ปดํฌ๋„ŒํŠธ๋Š” Consumer๋กœ ๊ฐ์‹ธ์ง„ ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์—์„œ Provider์—์„œ ์„ค์ •ํ•œ ๊ฐ’์„ props๋กœ ์ „๋‹ฌ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค.
  • ๋”ฐ๋ผ ์ „์—ญ์ ์œผ๋กœ ๊ฐ’์„ ๊ณต์œ ํ•ด์•ผํ•  ๊ฒƒ์ด ์žˆ์„ ๋•Œ์— ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

โ—props drilling ์ด๋ž€?

  • Props drilling์ด๋ž€ย ์ค‘์ฒฉ๋œ ์—ฌ๋Ÿฌ ๊ณ„์ธต์˜ ์ปดํฌ๋„ŒํŠธ์—๊ฒŒ props๋ฅผ ์ „๋‹ฌํ•ด ์ฃผ๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค.
    ํ•ด๋‹น props ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ์ปดํฌ๋„ŒํŠธ์—๊ฒŒ๊นŒ์ง€ ๋ง์ด๋‹ค.

๐ŸŸก ์‚ฌ์šฉ๋ฐฉ๋ฒ•

๋ฆฌ์•กํŠธ context ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ๋„ค ๋‹จ๊ณ„๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.
1. createContext ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด context ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.
2. ์ƒ์„ฑ๋œ context ๋ฅผ ๊ฐ€์ง€๊ณ  context Provider ๋กœ ์ปดํฌ๋„ŒํŠธ ํŠธ๋ฆฌ๋ฅผ ๊ฐ์‹ผ๋‹ค.
3. vlaue prop ์„ ์‚ฌ์šฉํ•ด context provider ์— ์›ํ•˜๋Š” ๊ฐ’์„ ์ž…๋ ฅํ•œ๋‹ค.
4. context consumer ๋ฅผ ํ†ตํ•ด ํ•„์š”ํ•œ ์ปดํฌ๋„ŒํŠธ์—์„œ ๊ทธ ๊ฐ’์„ ๋ถˆ๋Ÿฌ์˜จ๋‹ค.

  • context ๋ž€?
    • ๋ฐ์ดํ„ฐ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๊ฐ์ฒด. crateContext() ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.
  • Provider ์ปดํฌ๋„ŒํŠธ๋ž€ ?
    • context ๊ฐ์ฒด๋ฅผ ์ด์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ์ œ๊ณตํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ์ด๋‹ค. ๋ฐ์ดํ„ฐ๋ฅผ ์ œ๊ณตํ•  ๊ฐ’(value) ๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

- ๊ตฌ์ฒด์ ์œผ๋กœ ์•Œ์•„๋ณด์ž

import { createContext } from 'react';

const MyContext = createContext();
  • Context ๊ฐ์ฒด ์•ˆ์—๋Š” Provider๋ผ๋Š” ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋“ค์–ด์žˆ๋‹ค.
    ๊ทธ๋ฆฌ๊ณ , ๊ทธ ์ปดํฌ๋„ŒํŠธ๊ฐ„์— ๊ณต์œ ํ•˜๊ณ ์ž ํ•˜๋Š” ๊ฐ’์„ value ๋ผ๋Š” Props๋กœ ์„ค์ •ํ•˜๋ฉด ์ž์‹ ์ปดํฌ๋„ŒํŠธ๋“ค์—์„œ ํ•ด๋‹น ๊ฐ’์— ๋ฐ”๋กœ ์ ‘๊ทผ์„ ํ•  ์ˆ˜ ์žˆ๋‹ค.
function App() {
  return (
    <MyContext.Provider value="Hello World">
      <GrandParent />
    </MyContext.Provider>
  );
}
  • ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด, ์›ํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ์—์„œ useContext ๋ผ๋Š” Hook์„ ์‚ฌ์šฉํ•˜์—ฌ Context์— ๋„ฃ์€ ๊ฐ’์— ๋ฐ”๋กœ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค.
    ํ•ด๋‹น Hook์˜ ์ธ์ž์—๋Š” createContext๋กœ ๋งŒ๋“  MyContext๋ฅผ ๋„ฃ์œผ๋ฉด ๋œ๋‹ค.
import { createContext, useContext } from 'react';

function Message() {
  const value = useContext(MyContext);
  return <div>Received: {value}</div>;
}
  • ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์ค‘๊ฐ„ ์ค‘๊ฐ„ ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ฑฐ์ณ ์ „๋‹ฌํ•˜๋˜ Props๋ฅผ ์ง€์›Œ์ฃผ์–ด๋„๋œ๋‹ค.

- ์˜ˆ์‹œ

Context API๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ

function App() {
  const [data, setData] = useState("Hello, World!");

  return (
    <>
      <Header data={data} />
    </>
  );
}

function Header(props) {
  return <FirstContent data={props.data}/>;
}

function FirstContent(props) {
  return <SecondContent data={props.data}/>;
}

function SecondContent(props) {
  return <ThreeContent data={props.data}/>;
}

function ThreeContent(props) {
  return <p>WOW! {props.data}</p>;
}
  • ์œ„์˜ ์ฝ”๋“œ์—์„œ ๋ณด์ด๋“ฏ App ์ปดํฌ๋„ŒํŠธ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ด€๋ฆฌํ•˜๊ณ , ํ•ด๋‹น ๋ฐ์ดํ„ฐ๋ฅผ Header, Content, Footer ์ปดํฌ๋„ŒํŠธ๋กœ ์ „๋‹ฌํ•˜๊ณ  ์žˆ๋‹ค.
  • ์ด๋Ÿฌํ•œ Props Drilling ์ฝ”๋“œ๋Š” ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋” ๋งŽ์•„์งˆ์ˆ˜๋ก ๋ณต์žกํ•˜๊ณ  ์–ด๋ ค์›Œ ์งˆ ๊ฒƒ์ด๋‹ค. ์ด ๋ฐ์ดํ„ฐ๊ฐ€ ์–ด๋””์—์„œ ์˜ค๋Š”์ง€ ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ๋ฅผ ํƒ€๊ณ , ํƒ€๊ณ  ๊ฑฐ์Šฌ๋Ÿฌ ์˜ฌ๋ผ๊ฐ€์•ผํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํ™•์ธํ•˜๋Š” ๊ฒƒ๋„ ๋งค์šฐ ๋ถˆํŽธํ•ด์งˆ ๊ฒƒ์ด๊ณ ..

Context API๋ฅผ ์‚ฌ์šฉํ•œ ๊ฒฝ์šฐ

import React, { createContext, useState } from "react";

const DataContext = createContext();

function App() {
  const [data, setData] = useState("Hello, World!");

  return (
  <DataContext.Provider value={data}>
  <Header />
  </DataContext.Provider>
  );
}

function Header() {
  return <FirstContent />;
}

function FirstContent() {
  return <SecondContent />;
}

function SecondContent() {
  return <ThreeContent />;
}

function ThreeContent() {
  const data = useContext(DataContext);
  return <p>WOW! {data}</p>;
}
  • createContext() ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Context ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ , App ์ปดํฌ๋„ŒํŠธ์—์„œ ์ƒ์„ฑํ•œ data state ๋ฅผ DataContext.Provider ์˜ value prop ์œผ๋กœ ์ „๋‹ฌํ•œ๋‹ค.
  • ๊ทธ ๋‹ค์Œ ์‚ฌ์šฉํ•  ์ปดํฌ๋„ŒํŠธ์—์„œ useContext() ํ›…์„ ์‚ฌ์šฉํ•ด ์‚ฌ์šฉํ•ด์ฃผ๊ธฐ๋งŒ ํ•˜๋ฉด ๋œ๋‹ค. ์ •๋ง ๊น”๋”ํ•˜๋‹ค!

- ๋‚ด๊ฐ€ ์‹ค์ œ ์‚ฌ์šฉํ•œ ๋ฐฉ๋ฒ•

๋‚˜๋Š” firebase ์™€ nextron ์„ ๊ฐ€์ง€๊ณ  ์ฑ„ํŒ…์•ฑ์„ ๋งŒ๋“ค ๋•Œ ์œ ์ €์˜ ๋กœ๊ทธ์ธ ์—ฌ๋ถ€๋ฅผ ์ €์žฅํ•˜๋Š”๋ฐ์— ์‚ฌ์šฉํ–ˆ๋‹ค.
(์‚ฌ์‹ค ์ƒํƒœ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ธ recoil ์„ ์‚ฌ์šฉํ•ด์•ผํ•˜๋‚˜ ์‚ฝ์งˆํ–ˆ๋‹ค๊ฐ€, ์‚ฝ์งˆ ํ›„ ๋กœ๊ทธ์ธ ์—ฌ๋ถ€๋ฅผ ์ €์žฅํ•˜๋Š”๋ฐ์—๋Š” ์ ์ ˆ์น˜ ์•Š๋‹ค๋Š” ๊ฒƒ์„ ์•Œ์•˜๋‹ค...)
๋‹น์‹œ context api ๋Š” ์ฒ˜์Œ์ด์˜€๋˜ํ„ฐ๋ผ ์—„์ฒญ ๋”๋“ฌ๊ฑฐ๋ฆฌ๋ฉด์„œ ๋งŒ๋“ค์—ˆ๋˜ ๊ธฐ์–ต์ด..๐Ÿ˜ญ

์•„๋ž˜๋Š” crateContext() ๋ฉ”์†Œ๋“œ๋กœ ๊ธฐ์ดˆ ์ƒํƒœ๋ฅผ ์„ค์ •ํ•ด์ฃผ๊ณ ,
๋กœ๊ทธ์ธ ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ๊ด€์ฐฐํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ–ˆ๋‹ค.

// - AuthContext.tsx

export const AuthContext = createContext(undefined);

export const AuthContextProvider = ({ children }) => {

  const [currentUser, setCurrentUser] = useState<IUser>(null);
  
  useEffect(() => {
    // ํ˜„์žฌ ๋กœ๊ทธ์ธ๋œ ์‚ฌ์šฉ์ž ์ •๋ณด ๊ด€์ฐฐ
    const unsub = onAuthStateChanged(auth, user => {
      setCurrentUser(user);
    });

    // cleanup fn
    return () => {
      unsub();
    };
  }, []);
  return (
    <AuthContext.Provider value={{ currentUser }}>
      {children}
    </AuthContext.Provider>
  );
};

์ด ์•„๋ž˜๋Š” ๋งŒ๋“ค์–ด๋†“์€ context ๋ฅผ ์‚ฌ์šฉํ•œ ์ฝ”๋“œ๋‹ค.

function Navbar() {
  const auth = getAuth();
  // ํ˜„์žฌ ๋กœ๊ทธ์ธ๋œ ์‚ฌ์šฉ์ž ์ •๋ณด
  const { currentUser } = useContext(AuthContext);

  .
  .
  .

  return (
    <div className="navbar">
      <span className="username">
        ๐ŸŸข {currentUser ? currentUser.email : ""}
      </span>
      <button onClick={onClick}>Logout</button>
      <style jsx>{`

value ์— currentUser ๋ฅผ ์ „๋‹ฌํ•ด์„œ ๊ฑฐ์˜ ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ์—์„œ ์‚ฌ์šฉํ–ˆ๋‹ค.

๐ŸŸก ์ฃผ์˜ํ•  ์ 

  • ๋จผ์ €, context ๊ฐ€ ๋‚ด๋ ค์ฃผ๋Š” ๊ฐ’์€ ์—…๋ฐ์ดํŠธ๊ฐ€ ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค.
  • ๋งŒ์•ฝ ๋ฆฌ์•กํŠธ context provider ์— ๊ฐ์ฒด๋ฅผ ๋‚ด๋ ค์ฃผ๊ณ  ์žˆ๊ณ  ๊ทธ ๊ฐ์ฒด์˜ ํ”„๋กœํผํ‹ฐ๊ฐ€ ์—…๋ฐ์ดํŠธ๋œ๋‹ค๋ฉด ์–ด๋–จ๊นŒ?
    ๊ทธ context ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š” ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ์—์„œ ์žฌ๋ Œ๋”๋ง์ด ๋ฐœ์ƒํ•  ๊ฒƒ์ด๋‹ค(...)
  • state ๊ฐ€ ๊ฑฐ์˜ ์—†๋Š” theme ๋ฐ์ดํ„ฐ ๋“ฑ์— ์‚ฌ์šฉํ•ด์•ผ ์„ฑ๋Šฅ ์ด์Šˆ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์„ ๊ฒƒ์ด๋‹ค. ํ…Œ๋งˆ ๋ฐ์ดํ„ฐ๋Š” ์—…๋ฐ์ดํŠธ๊ฐ€ ์ž์ฃผ ๋˜์ง€ ์•Š์œผ๋‹ˆ๊นŒ ๋ง์ด๋‹ค. ์ด๋ฅผ ์ฃผ์˜ํ•ด์„œ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค!

์ฐธ๊ณ ์ž๋ฃŒ_1
์ฐธ๊ณ ์ž๋ฃŒ_2
์ฐธ๊ณ ์ž๋ฃŒ_3

profile
๊ธฐ์–ต๋ ฅ ์•ˆ ์ข‹์€ FE ๊ฐœ๋ฐœ์ž์˜ ๋ฉ”๋ชจ์žฅ

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