React

darkMode 적용

Asset Type
File Type
When to use
Reference
Created by
Created time
2022/03/13 14:50
Last edited time
2022/03/13 15:53
// useDarkMode.ts import { Dispatch, SetStateAction, useEffect, useState } from "react"; function useDarkMode(): [string, Dispatch<SetStateAction<string>>] { const [theme, setTheme] = useState( typeof window !== "undefined" ? localStorage.theme : "dark" ); const colorTheme = theme === "dark" ? "light" : "dark"; useEffect(() => { const root = window.document.documentElement; root.classList.remove(colorTheme); root.classList.add(theme); console.log(root); if (typeof window !== "undefined") { localStorage.setItem("theme", theme); } }, [theme]); return [colorTheme, setTheme]; } export default useDarkMode;
TypeScript
복사
svg로 구현하면 아래와 같이 지저분하다.
import useDarkMode from "../useDarkMode"; import Head from "next/head"; export default function Home() { const [colorTheme, setTheme] = useDarkMode(); return ( <div> <Head> <title>Dark mode demo</title> <meta name="description" content="Generated by create next app" /> <link rel="icon" href="/favicon.ico" /> </Head> {colorTheme === "light" ? ( <svg onClick={() => setTheme("light")} ... > <path ... /> </svg> ) : ( <svg onClick={() => setTheme("dark")} ... > <path ... /> </svg> )} </div> ); }
TypeScript
복사
이 경우는 svg에 바로 onclick 이벤트를 받는다. 나는 FontAwesomeIcon 컴포넌트 가져와서 사용하고 여기에 바로 onclick 이벤트 핸들러를 줄 수 없어서 button으로 감싸서 button에 줬다.
button으로 감싸면 중복된 코드가 늘어났다.
... return( <> {colorTheme === "light" ? ( <button onClick={() => setTheme("light")} > <FontAwesomeIcon icon={faSun} /> </button> ) : ( <button onClick={() => setTheme("dark")} > <FontAwesomeIcon icon={faMoon} /> </button> )} </> );
TypeScript
복사
삼항 연산자를 이용해서 dry하게 만드려면 바로 이전 상태를 가져와 사용해야 한다.(이렇게 하지 않으면 이미 변경된 state를 사용하게 되어 정상적으로 작동되지 않는다.)
setTheme(prev ⇒ prev === “dark” ? “light” : “dark”);
TypeScript
복사
완성하면 아래와 같다.
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faSun, faMoon } from "@fortawesome/free-regular-svg-icons"; import styles from "./DarkModeButton.module.scss"; import useDarkMode from "../../hooks/useDarkMode"; const DarkModeButton = (): JSX.Element => { const [colorTheme, setTheme] = useDarkMode(); return ( <button className={styles.el_darkModeBtn} onClick={() => setTheme((theme: string) => (theme === "dark" ? "light" : "dark")) } > <FontAwesomeIcon icon={colorTheme === "light" ? faSun : faMoon} /> </button> ); }; export default DarkModeButton;
TypeScript
복사