본문 바로가기
프론트엔드/React

리액트 Context API : 가게 사장님이 소비자에게 메뉴판을 제공하다.

by maverick11471 2024. 9. 17.

  기존에 우리는 컴포넌트간에 데이터를 주고받을 때, Parent와 Child 컴포넌트를 지정하고, props를 통해 전송하는 방법을 사용했었다. 그런데 만약 자식에게 전송하는 것이 반복된다면 props를 이용하는 것이 굉장히 비효율적일 수 있다. 실생활 예시로 들면 우리가 어머니 생신 때 생일카드를 작성해서 직접드리는 것이 효율적(props)이지만, 회사 내 공지사항을 전달할 때는 개개인별로 전송하는 것보다 단체로 전송하는 것이 더 효율적(Context API)이라 할 수 있다. 웹 페이지 게시판도 각각의 내용물만 달라질 뿐 전체적인 구성이나 디자인이 같다면 props의 전송보다는 Context API가 더 효율적이라 볼 수 있다.

  우선 Context API를 쉽게 암기하기 위해 우리는 이미지화 시킬 필요가 있다. 우리는 가게를 오픈한 사장님이 가게 손님에게 메뉴판을 제공하여 메뉴를 선택할 수 있도록 하는 이미지를 떠올릴 수 있다. 이와 비유하여 Context API의 주요 구성에 대해 알아보자.

1. Provider: 가게 사장
2. Consumer: 가게 손님
3. value: 메뉴판
4. createContext: 가게 오픈

 

 

  그렇다면 Context API에 대해 코드 작성하는 예시를 알아보자. 예시는 버튼을 클릭하면 다크모드로 전환할 수 있는 버튼을 만들어보려고 

한다.

 

1. darkMode.js

  가. 순서 (가게를 차리고 사장님이 메뉴판을 제공한다)

    1) (컴포넌트명)Context = createContext({state:{}, actions:{}}) '가게를 차린다'

        * Context를 만들고 그 안에 상태와 행동을 정의한다. 

    2) (컴포넌트명)Provider '사장님이 메뉴판을 제공한다'

        * {children}을 매개변수로 받는다. 이 변수명은 어떤것이든 상관없다. 'children' 은 자식컴포넌트를 뜻한다.

        * useState로 상태값을 정한다.

        * initialValue를 정해 state와 actions를 정한다. 이 때 ES6의 기법에 맞게 상태명만 정하면 자동적으로 해당 값이 전송될 수 있도록 한다. initialValue는 어떤 변수명을 지정해도 상관없다.

    3) <(컴포넌트명)Context.Provider value={initialValue}>

           {children}

        </(컴포넌트명)Context.Provider>

        * 자식 컴포넌트에게 initialValue를 전송해준다.

import {createContext, useState} from "react";

const DarkmodeContext = createContext({
    state: {
        theme: 'light'
    },
    actions: {
        setTheme: () => {
        }
    }
});

const DarkmodeProvider = ({children}) => {

    const [theme, setTheme] = useState('light');

    const initialValue = {
        state: {
            theme
        },
        actions: {
            setTheme
        }
    }

    return (
        <DarkmodeContext.Provider value={initialValue}>
            {children}
        </DarkmodeContext.Provider>
    )
};

const DarkmodeConsumer = DarkmodeContext.Consumer;

export {DarkmodeProvider, DarkmodeConsumer}

export default DarkmodeContext;

 

2. Header.js

  가. 순서 (손님이 메뉴판을 가지고 주문을 한다.)

    1) <(컴포넌트명)Consumer>

          * 설정할 내용들 *

        </(컴포넌트명)Consumer>

import React from 'react';
import DarkmodeContext, { DarkmodeConsumer } from "./darkmode";

const Header = () => {
    return (
        <DarkmodeConsumer>
            {({ state, actions }) => {
                const toggleTheme = () => {
                    actions.setTheme(prevTheme => (prevTheme === 'light' ? 'dark' : 'light'));
                };

                const headerStyle = {
                    backgroundColor: state.theme === 'light' ? '#fff' : '#333',
                    color: state.theme === 'light' ? '#000' : '#fff',
                    padding: '10px',
                    textAlign: 'center'
                };

                return (
                    <div style={headerStyle}>
                        <h1>Open</h1>
                        <button onClick={toggleTheme}>
                            Switch to: {state.theme === 'light' ? 'Dark' : 'Light'} Mode
                        </button>
                    </div>
                );
            }}
        </DarkmodeConsumer>
    );
};

export default Header;

 

3. App.js

  : 사장님과 손님이 가게에 함께 있는 모습을 상상한다.


import {DarkmodeProvider} from "./practice/darkmode";
import Header from "./practice/Header";

function App() {
  return (
    <>
      <DarkmodeProvider>
          <Header/>
      </DarkmodeProvider>
    </>
  );
}

export default App;