Study/React

[React] Context API 를 사용해서 다크모드 구현하기

다니니니 2024. 10. 12. 15:57
728x90

1. 서론

리액트의 Context API 는 컴포넌트 트리의 깊이에 관계없이 props 를 전달하지 않고도 컴포넌트 트리 전체에 데이터를 제공할 수 있다. Context는 전역 데이터를 관리하는 데 사용한다.

이 Context 를 이용해서 웹 애플리케이션에서 다크모드를 구현하고자 한다.

(에시는 https://daddda3232.tistory.com/72 여기서 사용했던것을 활용했다)

 

2. 본론

createContext 

createContext 는 Context 객체를 만든다.

const VillagerContext = createContext('light');

 

createContext 안에는 기본값을 넣어준다

여기서는 ligth 모드를 기본값으로 넣어줬다.

 

createContext 함수 호출로 생성된 컨텍스트 객체는 Provider 와 Consumer 라는 컴포넌트를 제공한다.

Provider 는 컨텍스트의 기능을 제공할 컴포넌트고,

Consumer 는Provider 가 제공한 기능을 사용하고 싶은 클래스 컴포넌트다.

여기서는 함수형 컴포넌트를 활용할 것이기 때문에 Consumer 는 사용하지 않는다.

대신 함수형 컴포넌트에서는 useContext 훅을 사용한다. 

 

Provider

Provider 는 value 와 children 속성이 있는 ProviderProps 속성을 제공한다. 

Provider 로 감싸서 컨텍스트의 값을 모든 내부 컴포넌트에 지정한다.

 

VillagerContext.js

import { createContext, useState } from "react";

export const VillagerContext = createContext('light');

export function VillagerProvider ({children}){
    const [theme, setTheme] = useState('light')

    const chgTheme = (mode) => {
        setTheme(mode);
    }
        
    return (
        <VillagerContext.Provider value={{theme, chgTheme}}>
            {children}
        </VillagerContext.Provider>
    )
}

index.js

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
    <VillagerProvider>
        <App4 />
    </VillagerProvider>
);

 

위와 같이 사용할 수 있다.

VillagerContext.js 의 코드를 해석하자면 Context를 사용할 Provider 함수를 만든 후, 그 안에 사용할 로직을 작성한다.

위에서는 다크모드로 바꿔주는 로직이다. 

Provider로 context 값을 전달해줄 컴포넌트를 감싸준다. 여기서는 좀 더 재사용성을 높이기 위해 children으로 썼다.

그러고나서 index.js 에 가서 provider 함수를 불러온 후 컨텍스트 값을 전달할 자식 컴포넌트를 넣었다.

value에는 전달할 컨텍스트 값을 넣는다.

 

useContext

useContext 는 컨텍스트 객체가 제공하는 Provider 컴포넌트의 value 속성값을 얻을 수 있게하는 목적으로 사용되는 훅이다.

useContext 는 Provider 의 value 속성값을 반환한다.

 

App.js

function App() {
const {theme, chgTheme} = useContext(VillagerContext);

const [name, setName] = useState('릴리안')
const [day, setDay] = useState('5월 9일생')

const clickVillger = (e) => {
  let vName = e.currentTarget.innerText
  let vDay = e.currentTarget.lastChild.getAttribute('data-day')
  setName(vName)
  setDay(vDay)
}

  return (
    <div className={`App ${theme}`}>
      <DarkmodeToggle chgTheme={chgTheme}/>
      <Villagers villager={villager} click={clickVillger}/>
      <VillagerInfo name={name} day={day}/>
    </div>
  );
}

DarkmodeToggle.js

export default function DarkmodeToggle({chgTheme}) {
  return (
    <>
        <input type='checkbox' id='darkmode-toggle' onChange={(e) => chgTheme(e.target.checked ? 'dark' : 'light')}/>
        <label htmlFor='darkmode-toggle' className='darkmode-toggle'></label>
    </>
  )
}

 

위에서는 useContext 훅을 이용해서 theme 이라는 변수와 chgTheme 이라는 theme state 변수를 변경해주는 함수를 불러왔다.

그것을 DarkmodeToggle 이라는 컴포넌트로 전달해서 input이 체크되어 있으면 dark 모드로 아니라면 light 모드로 되도록 구현했다.

전체를 감싸고 있는 App 이라는 div 에 클래스를 가지고 있을때의 배경색을 주는 방식으로 다크모드를 구현했다.

.App.light {
  background-color: #ebebeb;
  color : #242424;
}

.App.dark {
  background-color: #242424;
  color : #ebebeb;
}

 

그래서 theme 이라는 변수에는 ligth 혹은 dark 라는 값을 가질 수 있는데,

light 클래스를 가지고 있으면  ligth 모드로 dark 클래스를 가지고 있으면 dark 모드로 되도록 간단하게 구현했다.

 

3. 결론

Context API를 이용해서 테마를 바꿔주는 방법을 구현해봤다.

이전에 부트캠프에서 1차 프로젝트를 했을 때 라이트모드/다크모드가 있으면 좋겠다는 생각을 했는데, 리액트의 useContext를 이용해서 간편하게 구현할 수 있는 방법을 알게되서 뿌듯하다.

2차 프로젝트를 했을 때는 유저 권한을 전역으로 관리하기 위해서 redux 와 함께 사용했었다.(https://daddda3232.tistory.com/93)

지금 생각해보니 굳이 redux 까지 쓸 필요가 있었을까 싶지만 아마 그때 이미 헤더를 redux 를 이용한 변수로 구현해놔서 저런식으로 했었다. 

저때는 시간에 쫓겨 저 코드의 의미에 대해서 덜 알아보고 썼었는데 이번 기회에 제대로 알게 되서 뿌듯하고 다른 프로젝트를 할 때 redux 나 context 중 더 나은 방법으로 효율적인 코드를 짜도록 해야겠다. 

 

4. Reference

도서 : 리액트로 웹앱 만들기

https://product.kyobobook.co.kr/detail/S000212754474

 

Do it! 리액트로 웹앱 만들기 with 타입스크립트 | 전예홍 - 교보문고

Do it! 리액트로 웹앱 만들기 with 타입스크립트 | 프런트엔드 개발자 채용 공고에서 인기 있는 자격 요건은 모두 갖췄다! 최신 웹 개발 트렌드를 반영하고 실무 코드로 가득 채운 ‘리액트 전문서

product.kyobobook.co.kr

 

 

https://react.dev/learn/passing-data-deeply-with-context

 

Passing Data Deeply with Context – React

The library for web and native user interfaces

react.dev

 

https://react.dev/reference/react/useContext

 

useContext – React

The library for web and native user interfaces

react.dev

https://www.youtube.com/watch?app=desktop&v=S-T9XoCMwt4

 

 

 

 

 

728x90