본문 바로가기
React

[React] useContext api

by jyee 2024. 8. 27.
728x90
반응형

 

 

 

useContext 훅은 어떻게 사용할까?

리액트의 일반적인 데이터 흐름은 부모 컴포넌트에서 자식 컴포넌트로 props를 통해 '단방향'으로 흐른다. 엄청 큰 컴포넌트 트리가 있다고 가정할 때 공통적으로 필요한 전역적인 데이터가 있을 수 있다. 예를 들어 userdata
전역 데이터를 일일이 props로 단계별로 전달해야 한다면 정말 비효율 적이다.
리액트는 이러한 문제점을 해결해 주는 Context API를 제공한다.

Context는 앱 안에서 전역적으로 사용되는 데이터를 여러 컴포넌트끼리 쉽게 공유할 수 있는 방법을 제공한다. Context를 사용하면 Props로 데이터를 일일이 전달해 주지 않아도 해당 데이터를 가지고 있는 상 위 컴포넌트에 그 데이터가 필요한 하위 컴포넌트가 접근할 수 있다. 즉 사용자 정보, 테마, 언어 등 전역적인 데이터를 전달하기에 정말 편리하다.

상위 컴포넌트의 data가 필요한 하위 컴포넌트들은 useContext 훅을 사용해서 해당 데이터를 받아오기만 하면 된다.
useContext는 Context로 분류한 데이터를 쉽게 받아올 수 있게 도와주는 역할을 한다.

 

Q. context가 이렇게 좋은데 그럼 굳이 왜 props를 사용하는가?

context는 꼭 필요할 때만 사용한다. context를 사용하면 컴포넌트를 재사용하기 어려워질 수 있다. context의 주된 목적인 다양한 레벨이 있는 많은 컴포넌트들에게 전역적인 데이터를 전달하기 위함이다.

// 최상위 컴포넌트
import { useState } from "react";
import "./App.css";
import Page from "./Compopnents/Page";


function App() {
  // 햔제 App 이 다크모드인지 아닌지 true false 로 정보를 받고 있다. 
  const [isDark, setIsDark] = useState(false);
  
  // Page 자식 컴포넌트에게 해당 데이터를 props로 넘겨 주고 있다. 
  return <Page isDark={isDark} setIsDark={setIsDark}/>
}
export default App;

 

🐓 Page 컴포넌트

// page 컴포넌트
import React, { useContext } from "react";
import Content from "./Context";
import Header from "./Header";
import Footer from "./Footer";

const Page = ({isDark, setIsDark}) => {
  return (
    <div className="page">
      <Header isDark={isDark}/>
      <Content isDark={isDark}/>
      <Footer isDark={isDark} setIsDark={setIsDark}/>
    </div>
  );
};

export default Page;
  • 전체화면을 담고 있는 컴포넌트
  • 3개의 자식 컴포넌트를 가지고 있다.
  • {isDark, setIsDark} 를 props로 받아오고 있다.
  • isDark 를 모든 자식 컴포넌트에게 전달을 해주고, setIsDark는 Footer에게 전달해준다.

 

🐥 Header 컴포넌트

import React from "react";

const Header = ({ isDark }) => {
  return (
    <header
      className="header"
      style={{
        backgroundColor: isDark ? "black" : "lightgray",
        color: isDark ? "white" : "black",
      }}
    >
      <h1>Welcome 홍길동</h1>
    </header>
  );
};

export default Header;
  • isDark 를 props로 전달받고 있다.
  • header 태그는 isDark가 true 이면 배경이 black, false면 lightgray 아래 글씨 색상도 동일하게 작동한다.

 

🐥 Content 컴포넌트

import React from "react";

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

export default Content;
  • isDark 를 props로 전달받고 있다.
  • header 와 마찬가지고 isDark 가 true냐 false이냐에 따라 배경과 글자색상이 달라진다.

 

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;
  • isDark와 setIsDark를 props로 전달받고 있다.
  • isDark 가 true냐 false이냐에 따라 배경과 글자색상이 달라진다.
  • button 이 클릭될 때마다 toggleTheme 함수가 실행된다.
  • toggleTheme 는 현재 isDark가 true 면 false로 바꿔주고 false 면 true 로 바꿔준다.

 App 컴포넌트가 가지고 있는 isDark 데이터를 모든 하위 컴포넌트에게 props를 사용하지 않고 context를 사용해서 공유

 

react context를 만들려면 가장 먼저 createContext를 import 시켜줘야한다.

import { createContext } from "react";

// 기본값으로는 null을 넣어준다.
export const ThemeContext = createContext(null);

 

App 컴포넌트로 돌아가서 위 context를 import 시켜준다.

  • 그리고 page 컴포넌트를 만들어준 context의 provider로 감싸준다.
  • context의 provider는 value 라는 props를 받는데 이 안에는 전달하고자 하는 데이터를 넣어준다.
  • ThemeContext 감싸는 모든 하위 컴포넌트는 props를 사용하지 않고 value로 넣어준 값에 접근할 수 있다. 그리고 페이지 컴포넌트가 갖는 값들을 지워준다.
import { useState } from "react";
import "./App.css";
import Page from "./Compopnents/Page";
import { ThemeContext } from "./context/ThemeContext";

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

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

 

page 컴포넌트에서 인자로 받아오는 {isDark, setIsDark} 를 지워준다. 그리고 중간 컴포넌트이니 isDark와 가 필요가 없다.

import React from "react";
import Content from "./Context";
import Header from "./Header";
import Footer from "./Footer";

// isDark 를 실질적으로 사용하지 않고, 자녀 컴포넌트들에게 전달하는 역할
// data 필요하지 않음 !
const Page = () => {
  return (
    <div className="page">
      <Header/>
      <Content/>
      <Footer/>
    </div>
  );
};

export default Page;

 

*****자식컴포넌트들에서 props 지워주기

header에서는 props를 지워주고 useContext 훅을 사용해 ThemeContext를 불러온다.

import { useContext } from "react";
 // 📌 
import { ThemeContext } from "../context/ThemeContext";

const Header = () => {
  // 📌 
  const { isDark } = useContext(ThemeContext);
  return (
    <header
      className="header"
      style={{
        backgroundColor: isDark ? "black" : "lightgray",
        color: isDark ? "white" : "black",
      }}
    >
      <h1>Welcome 홍길동!</h1>
    </header>
  );
};

export default Header;

 

 

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

const Content = () => {
    // 📌 
  const { isDark } = useContext(ThemeContext);

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

export default Content;

 

 

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

const Footer = () => {
  // 📌
  const { isDark, setIsDark } = useContext(ThemeContext);
  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;
728x90
반응형

'React' 카테고리의 다른 글

[React]useCallback  (0) 2024.09.03
[React] useMemo  (2) 2024.09.03
[React]useReducer  (0) 2024.08.20
[React] react-hook-form 사용하기  (0) 2024.08.13
[React] react-hook-form useRef 사용  (0) 2024.08.13