즐코

Context API 복습 본문

React

Context API 복습

YJLEE_KR 2022. 5. 11. 02:02

redux라이브러리를 사용하겠지만,, contextAPI 복습을 해보았다.

원래 context는 Redux에서 나온 개념인데, redux 만든 사람이 react팀으로 가면서 해당 context API 를 만들었다는 얘기가 있다.

 

암튼, 전역적으로 여러 컴포넌트 내에서 쓰일 데이터가 있다면 이 context API를 사용하는 게 좋다.

ex) 로그인한 사용자 정보, 페이지 테마 (다크/라이트모드), 사용언어 등등..

 

자세히 예를 들자면, 

App -> Toolbar -> ThemeButton 이런식으로 컴포넌트들이 있고, ThemeButton만 App의 특정 props가 필요하다고 가정한다.

이 때, context API 가 없었다면, props 가 필요없는 Toolbar 컴포넌트가 쓸데없이 그 props를 받아서 자식 컴포넌트인 ThemeButton에게 전달해줘야한다. 

 

그렇다고 props를 사용하지 않는 건 아니라고 한다. 

 

- context 를 사용하면 컴포넌트를 재사용하기 어려워진다고 한다.

- context 를 사용하는 이유가 prop drilling 을 피하기 위한 목적이라면 Component Composition(컴포넌트 합성) 을 고려해보라고 한다. 컴포넌트 합성에 관하여 따로 포스팅하였다.

 

 

1. 전역상태를 담을 Context 파일 따로 만들기 

 

우선 src-context를 관리할 폴더를 따로 만들고 그 안에 전역으로 쓰고자하는 context들별로 파일을 만들어준다.

테마 관리용 컨텍스트 / 유저정보 컨텍스트 파일을 만들었음

 

 

createContext()

각 context파일들에는 createContext 를 가져와서 전역상태를 만들어준다.

- createContext()의 인자값으론 초기값을 넣어준다.

 

- 상태 공유를 위해 다른 컴포넌트를 감싸는 컴포넌트를 만든다고 보면 쉽다. 

<ThemeContext></ThemeContext>  <UserContext></UserContext> 가 만들어진거다. 

 

// ThemeContext.js
import { createContext } from 'react'
export const ThemeContext = createContext(null);

//  UserContext.js
import { createContext } from "react";
export const UserContext = createContext(null)

 

2. 위에서 만든 context 컴포넌트를 가져와서 전역 상태를 공유할 컴포넌트들을 감싸준다. 

 

Context 객체 안에는 Provider라는 컴포넌트가 들어있다. 

궁금해서 Mycontext.Provider 를 출력해보니 아래와 같이 _context를 가지고 있는 객체가 떨어진다.

createContext()의 인자로 넣어준 초기값 ("default value")도 가지고 있다.

import { createContext } from "react";
import GrandParent from "./components/GrandParent";

export const Mycontext = createContext("default value");

function App() {
  console.log(Mycontext.Provider);
  return (
    <Mycontext.Provider value="my context">
      <GrandParent />
    </Mycontext.Provider>
  );
}

export default App;

context.Provider 출력값

 

이 각 컨텍스트.Provider를 써줘야 상태 공유가 가능하며, value 라는 props로 전역 상태 값을 넘겨야 자식 컴포넌트들에서 해당 값에 바로 접근이 가능하다

import { useState } from "react";
import Page from "./components/Page";
import { ThemeContext } from "./context/ThemeContext";
import { UserContext } from "./context/UserContext";

const App = () => {
  const [isDark, setIsDark] = useState(false)
  const user = {
    idx: 1,
    userid: 'yjlee',
    level: 2,
  }
  return (
    <UserContext.Provider value={user}>
      <ThemeContext.Provider value={{ isDark, setIsDark }} >
        <Page />
      </ThemeContext.Provider>
    </UserContext.Provider>
  );
}

export default App;

 

 

3.  useContext 메소드를 써서 필요한 컴포넌트들만 전역 값을 쏙 빼다가 쓴다. 

 

 

Page.jsx : 컴포넌트들을 감싸고 있는 Page는 context가 필요없어서 가져오지 않았다! 

즉, props를 쓸때는 부모 컴포넌트가 자기자신이 필요 없는데도 자식에게 전달해야할때 props를 당겨왔지만, context를 쓰면 굳이 가져올 필요가 없다. 

import Header from "./Header";
import Content from "./Content";
import Footer from "./Footer";

const Page = () => {

  return (
    <div className="page">
      <Header />
      <Content />
      <Footer />
    </div>
  );
};

export default Page;

 

Content.jsx : 이렇게 필요한 컴포넌트만 가져와서 쓴다. 

useContext()

useContext() 로 전역 상태 value 에 바로 접근할 수 있다.

인자값으론 가져올 전역상태값, 즉 createContext로 만든 전역상태를 가져와서 넣어줘야한다!

useContext(ThemeContext) 나 useContext(UserContext) 를 출력해보면,

app.js에서 넘긴 value가 그대로 넘어온 걸 확인할 수 있다. 

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

const Content = () => {
  const { isDark } = useContext(ThemeContext)
  const { userid, level } = useContext(UserContext)
  return (
    <div className="content"
      style={{
        backgroundColor: isDark ? 'black' : 'white',
        color: isDark ? 'white' : 'black'
      }}>
      <p>안녕하세요! {userid}님</p>
      <p>현재 레벨은 {level} 입니다.</p>
    </div>
  )
}

export default Content;

 

 

Header.jsx, Footer.jsx도 context를 가져왔는데, 개념은 같으니 생략

 

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

Comments