FrontEnd/React

React Hooks - useContext + Context API

NandaNanda 2024. 3. 27. 21:06

참고: https://www.youtube.com/watch?v=LwvXVEHS638&list=PLZ5oZ2KmQEYjwhSxjB_74PoU6pmFzgVMO&index=5

 

 

https://react.dev/reference/react/useContext  이문서를 봐라. 모든게 여기서 부터 시작하고 여기서 부터 끝난다. 이거 해석하면 매번 두려움에 떨지 않아도 된다.

리엑트에서 일반적인 데이터 흐름은 위에서아래로, 즉, 부모 컴포넌트에서 자식 컴포넌트로 props를 통해서 전달됩니다.

 

props를 통해 데이터를 전달할 때는 위 그림과 같이 부모 컴포넌트에서 일일히 자식 컴포넌트에 props를 넣어서 단계별로 전달한다.

 

1️⃣ contextAPI와 useContext 사용이유

🤬 전역적인 정보들을  props로 전달하려면 단계별로 일일이 다 써주고, 수정시에도 불편하다. 🤬

전역적인 정보: User, 테마, 언어

 

✅  이럴때 사용하는 contextAPI, useContext ✅

 

리액트에서는 이러한 문제점을 해결하기 위해서 contextAPI를 제공한다.

context는 앱안에서 전역적으로 사용되는 데이터들을  여러컴포넌트끼리 쉽게 공유할 수 있는 방법을 제공한다.

 

➡️ 일일이 props로 제공하지 않아도 상위컴포넌트에서 전역적인 정보를 해당 컴포넌트로 바로 제공할 수 있어서 편리

2️⃣ useContext 사용법

useContext란? context로 공유한 데이터들을 쉽게 받아올수 있도록 도와주는 훅

context의 목적은 다양한 레벨에 있는 많은 컴포넌트들에게 전역데이터를 공유하기 위함임. prop drillring? 최종적으로 props가 필요한 컴포넌트까지 props를 전달하기 위해 그 사이의 많은 컴포넌트가 모두 props를 물려받아야 하는 현상

 

🔫 다크모드 만들어보기 🔫

1. contex이름.js 파일을 생성한다.

ThemeContext.js이름으로 생성함

2. createContext를 import해주기

import {createContext} from 'react';

만들어준 파일의 상단에 import해준다.

3. context 생성하기

export const ThemeContext = createContext(초기값);

✔️ 여기까지가

①ThemeContext라는 이름을 가진,

②전역에서 사용할,

context를 js파일로 생성한것.✔️

4. ThemeContext를 사용하고 싶은 곳에 import 해주기

import { ThemeContext } from './ThemeContext';

 

 

5. 사용하고 싶은곳을 ThemeContext로 감싸주기

return (
<ThemeContext.Provider>
	<Page/>
</ThemeContext.Provoder>
);

 

<Page>라는 컴포넌트의 하위부터 사용할 계획이라서 <Page>를 감쌌다.

 

 

6. context의 provider는 value라는 prop을 받는다. 

value안에는 전달하고자 하는 데이터를 넣어준다.

const [isDark, setIsDark] = useState(false);


return (
<ThemeContext.Provider value={{isDark, setIsDark}}>
	<Page />
</ThemeContext.Provoder>
)

 

isDark, setIsDark를 내려보내주고 싶어서 value값으로 넣어주었다.

이렇게 ThemeContext가 감싼 그 아래있는 모든 하위 컴포넌트는 isDark, setIsDark에 props사용없이 접근할 수 있게 됩니다.

 

🤩 Page 컴포넌트안에 넣어줬던 props인isDark={isDark} setIsDark={setIsDark}는 이제 지워줘도 된다. (원래 적어놓았다면)
(page컴포넌트는 정보가 필요한 당사자는 아님! ➡️ 하위컴포넌트중 props가 필요한 곳에서 바로 받아오면 된다)

 

 

7. useContext 훅을 사용해서 받아오기

7-1.

각각 파일의 상단에 useContext와 ThemeContext를 import해주어야한다.

7-2. useContext해주기

 

📚 isDark가 필요한 Header와 Content

 const { isDark } = useContext(ThemeContext);

 

📚 isDark, SetIsDark가 필요한 Footer

 const { isDark, setIsDark } = useContext(ThemeContext);

 

 

끝!!

👍  중간컴포넌트에서는(여기서는 Page컴포넌트) props를 안써도 된다. 👍

짜잔!! 다크모드가 구현되었다. 

전체적인 코드를 아래와 같다.

//ThemeContext.js
import { createContext } from "react";

export const ThemeContext = createContext(null);

//App.js
import React, { useState } from "react";
import "./App.css";
import Page from "./Page";
import { ThemeContext } from "./ThemeContext";

export default function App() {
  const [isDark, setIsDark] = useState(false);

  return (
    <ThemeContext.Provider value={{ isDark, setIsDark }}>
      <Page />;
    </ThemeContext.Provider>
  );
}


//Page.js
import React from "react";
import Header from "./Header";
import Content from "./Content";
import Footer from "./Footer";

export default function Page() {
  return (
    <div className="page">
      <Header />
      <Content />
      <Footer />
    </div>
  );
}


//Header.js
import React, { useContext } from "react";
import { ThemeContext } from "./ThemeContext";

export default function Header() {
  const { isDark } = useContext(ThemeContext);

  return (
    <header
      className="header"
      style={{
        backgroundColor: isDark ? "black" : "lightgrey",
        color: isDark ? "white" : "black",
      }}
    >
      <h1>모드 테스트중!!!</h1>
    </header>
  );
}

//Content.sj
import React, { useContext } from "react";
import { ThemeContext } from "./ThemeContext";

export default function Content() {
  const { isDark } = useContext(ThemeContext);

  return (
    <div
      className="content"
      style={{
        backgroundColor: isDark ? "black" : "white",
        color: isDark ? "white" : "black",
      }}
    >
      <p>화이팅 화이팅 화이팅 🔥</p>
    </div>
  );
}


//Footer.js
import React, { useContext } from "react";
import { ThemeContext } from "./ThemeContext";

export default function Footer() {
  const { isDark, setIsDark } = useContext(ThemeContext);

  const onToggle = () => {
    setIsDark(!isDark);
  };

  return (
    <footer
      className="footer"
      style={{
        backgroundColor: isDark ? "black" : "white",
        color: isDark ? "white" : "black",
      }}
    >
      <button className="button" onClick={onToggle}>
        Mode Change
      </button>
    </footer>
  );
}

 

위의 context를 사용하지 않고 순전히 props, state를 사용하여 만든 코드(아래)

폴더구조는 이와같다. components폴더를 새로 만들고 그 안에 jsx파일들을 만들어 주었다. 그리고 UI를 위해 디자인 코드를 App.css파일에 넣어주었다.

//Content.jsx
import React from "react";

const Content=({isDark})=>{
    return (
        <div className="content"
        style={{background:isDark?'black':'white',
        color:isDark?'white':'black',}}>
            <p>홍길동님, 좋은 하루되세요</p>
        </div>
    );   
};
export default Content;

//Footer.jsx

import React from "react";
const Footer=({isDark,setIsDark})=>{

    const toggleTheme=()=>{
        setIsDark(!isDark);
    };
    return(
    <footer className="footer"
    style={{backgroundColor:isDark?'black':'lightgray',}}>

        <button className="button" onClick={toggleTheme}>Dark Mode</button>
    </footer>);
};
export default Footer;



//Header.jsx

import React from "react";

//부모 컴포넌트(Page)로부터 물려받은 props(isDark)
const Header=({isDark})=>{
    return(
        <header
            className="header"
            style={{backgroundColor:isDark?'black':'lightgray', color:isDark?'white':'black',}}
>
    <h1>Welcome 홍길동</h1>
        </header>
    );
};
export default Header;



//Page.jsx
import React from 'react';
import Content from './Content';
import Footer from './Footer';
import Header from './Header';

//부모컴포넌트(App)에서 받은 props를 
const Page=({isDark, setIsDark})=>{
    return(
        <div className="page">
            {/* 자식컴포넌트(Header, Footer, Content)에게 전달하고 있다. props drilling이 발생하고 있음 */}
            <Header isDark={isDark}/>
            <Content isDark={isDark}/>
            <Footer isDark={isDark} setIsDark={setIsDark}/>
        </div>
    );
};

export default Page;



//App.js
import { useState } from "react";
import './App.css';
import Page from './components/Page';

const App=()=>{
  const [isDark, setIsDark]=useState(false);

  //자식 컴포넌트(Page)에게 props로 상태를 넘기고 있다.
  return <Page isDark={isDark} setIsDark={setIsDark}></Page>
}

export default App;

//index.css에 올릴 코드는 https://codepen.io/Coding-Star/pen/MWELozJ  여기에