테마모드 적용하기(feat.다크모드)
요즘 웹 대부분은 테마가 기본적으로 적용되어 있어서 사용자의 편의에 맞게 다크 모드, 라이트 모드로 화면을 볼 수 있는 편의성을 제공하고 있습니다. React로도 이 두가지 테마 모드를 쉽게 적용할 수 있는데 오늘 이 방법을 정리해보려고 합니다.
✏️ styled-components
React에서 다양한 방법으로 테마 모드를 적용할 수 있겠지만 styled-components를 이용하여 테마 모드를 적용하는 방법을 알아보려고 합니다.
styled-components 설치
> npm i styled-components
> npm i @types/styled-components // typescript 사용시
styled-components가 설치되어 있지 않다면 우선 터미널을 통해 styled-components를 설치해 줍니다.
이번 테마 적용 방법은 Typescript는 사용하지 않고 적용하는 방법을 정리할 예정입니다. 추후 Typescript까지 연동하여 테마를 적용하는 방법도 정리하겠습니다.
ThemeProvider
styled-components를 이용하여 테마를 적용하려면 ThemeProvider를 적용해서 사용해야 합니다.
styled-components의 공식문서를 보면 테마 구성을 위한 요소로 ThemeProvider 를 다음과 같이 소개하고 있습니다.
Injects the theme into all styled components anywhere beneath it in the component tree, via the context API.
(컨텍스트 API를 통해 구성 요소 트리에서 테마 아래에 있는 모든 스타일 구성 요소에 테마를 삽입합니다.)
import styled, { ThemeProvider } from 'styled-components'
const Box = styled.div`
color: ${props => props.theme.color};
`
render(
<ThemeProvider theme={{ color: 'mediumseagreen' }}>
<Box>I'm mediumseagreen!</Box>
</ThemeProvider>
)
결론은 ThemeProvider의 props로 theme를 전달해주면 그 아래에 있는 모든 component들은 styled를 사용해 스타일을 정의할 때 이 theme 값을 사용할 수 있습니다.
theme.js
export const lightTheme = {
bgColor: '#fff',
textColor: '#222',
accentColor: '#12cbef',
};
export const darkTheme = {
bgColor: '#282c35',
textColor: '#fff',
accentColor: '#ffe246',
};
export const theme = {
lightTheme,
darkTheme,
};
export default theme;
테마 화면에서 사용할 컬러 값을 각 테마에 맞게 정의합니다.
App.js
import React from 'react';
import styled, { createGlobalStyle, ThemeProvider } from 'styled-components';
import reset from 'styled-reset';
import { darkTheme, lightTheme } from './theme';
const GlobalStyle = createGlobalStyle`
${reset}
body {
background-color: ${(props) => props.theme.bgColor};
color:${(props) => props.theme.textColor}
}
`;
function App() {
const isDarkMode = false;
return (
<>
<ThemeProvider theme={isDarkMode ? darkTheme : lightTheme}>
<GlobalStyle />
<Home />
</ThemeProvider>
</>
);
}
export default App;
코드를 보면 ThemeProvider를 App.js의 최상단에 감싼 후 body에 theme에 적용한 값을 props로 불러와서 적용했습니다. 위의 코드에서 가장 중요한 부분 중 하나는 테마 값을 적용하고 그 값을 Global 스타일에 적용한 부분입니다. 이렇게 적용을 하면 각 테마에 맞게 화면의 값이 변경됩니다.
body {
background-color: ${(props) => props.theme.bgColor};
color: ${(props) => props.theme.color};
}
그리고 화면 코드 분기를 위해 isDarkMode 라는 변수를 만들어서 해당 변수의 값에 맞추어 테마를 적용시킵니다.
isDarkMode 값을 true로 바꾸면 다크테마가, false로 바꾸면 라이트 테마가 적용되는 것을 볼 수 있습니다. 하지만 이대로 사용하려면 직접 값을 변경해 주어야 하니 이제는 토클 버튼을 적용하여 해당 값이 클릭 시 변경될 수 있게 만들겠습니다.
App.js
import React, { useState } from 'react';
import styled, { createGlobalStyle, ThemeProvider } from 'styled-components';
import reset from 'styled-reset';
import { darkTheme, lightTheme } from './theme';
const GlobalStyle = createGlobalStyle`
${reset}
body {
background-color: ${(props) => props.theme.bgColor};
color:${(props) => props.theme.textColor}
}
`;
function App() {
const [isDarkMode, setIsDarkMode] = useState(false);
const toggleDarkMode = () => {
setIsDarkMode((prev) => !prev);
};
return (
<>
<ThemeProvider theme={isDarkMode ? darkTheme : lightTheme}>
<GlobalStyle />
<Home isDarkMode={isDarkMode} toggleDarkMode={toggleDarkMode} />
</ThemeProvider>
</>
);
}
export default App;
useState를 이용하여 상태값의 변화에 따라 해당 값이 변할 수 있도록 변수에 값을 적용해주고 Home 컴포넌트에 props로 다크 모드 여부를 의미하는 isDarkMode와 모드를 바꿔주는 토글 함수 toggleDarkMode를 전달합니다.
Home.js
import React from 'react';
import styled from 'styled-components';
import { BsFillSunFill, BsFillMoonFill } from 'react-icons/bs';
...
function Home({ isDarkMode, toggleDarkMode }: IHome) {
return (
<>
<header>
<HeaderLogo className="header__logo">HEO.D.K</HeaderLogo>
<button
type="button"
onClick={toggleDarkMode}
isDarkMode={isDarkMode}
>
{isDarkMode ? <BsFillSunFill /> : <BsFillMoonFill />}
</button>
</header>
<article>
<p>다크모드/라이트 모드</p>
</article>
</>
);
}
export default Home;
토글버튼은 react-icons에서 아이콘에서 자신이 원하는 다양한 모양으로 적용할 수 있습니다.
적용 화면