λ°λ‘ κ°κΈ° : https://light9639.github.io/Styled-Components-Dark-Mode/
![]() |
![]() |
---|
β¨ π Styled-Themingμ μ΄μ©νμ¬ λ§λ DarkMode μμ λ¬Έμμ λλ€. β¨
- React μμ±
npm create-react-app my-app
# or
yarn create react-app my-app
- viteλ₯Ό μ΄μ©νμ¬ νλ‘μ νΈλ₯Ό μμ±νλ €λ©΄
npm create vite@latest
# or
yarn create vite
- ν°λ―Έλμμ μ€ν ν νλ‘μ νΈ μ΄λ¦ λ§λ ν React μ ν, Typescirpt-SWC μ ννλ©΄ μμ± μλ£.
- styled-components, styled-theming μ€μΉνκΈ°
$ npm install styled-components styled-theming
# or
$ yarn add styled-components styled-theming
components
νμΌμ μλThemeContext
,GlobalStyle
μ»΄ν¬λνΈλ₯Ό κ°μ Έμ¨λ€.MyThemeProvider
λApp
μ κ°μΈμ€λ€.GlobalStyle
λ₯Ό λ£μΌλ©΄ μ μλ³μλ‘ νμ©μ΄ κ°λ₯νλ€.
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
import { MyThemeProvider } from "@components/ThemeContext";
import GlobalStyle from '@components/GlobalStyle'
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<React.StrictMode>
<GlobalStyle />
<MyThemeProvider>
<App />
</MyThemeProvider>
</React.StrictMode>,
)
- λ²νΌμ ν΄λ¦νλ©΄ ν λ§κ° λ°λλλ‘ μ€μ ν¨.
import * as React from "react";
import { useTheme } from "@components/ThemeContext";
import styled, { withTheme } from "styled-components";
import { buttonBackgroundColor, buttonTextColor } from "@components/theme";
import reactLogo from "./assets/react.svg";
interface PropsType {
theme: {
mode: string;
}
}
function App(props: PropsType) {
const themeToggle: any = useTheme();
const Button = styled.button`
background: ${buttonBackgroundColor};
border: none;
border-radius: 0.35rem;
box-shadow: none;
color: ${buttonTextColor};
cursor: pointer;
font-size: 1.25rem;
padding: 1rem 2rem;
`;
return (
<header className="App-header">
<img
src={reactLogo}
className="App-logo"
alt="logo"
/>
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<p>
<Button onClick={() => themeToggle.toggle()}>
{props.theme.mode === "dark"
? "Switch to Light Mode"
: "Switch to Dark Mode"}
</Button>
</p>
</header>
);
}
export default withTheme(App);
createGlobalStyle
μimport
ν νGlobalStyle
λ³μμ μ μ₯νλ€.
import { createGlobalStyle } from "styled-components";
const GlobalStyle = createGlobalStyle`
.App {
font-family: sans-serif;
text-align: center;
}
body {
margin: 0;
padding: 0;
}
.App-logo {
animation: App-logo-spin infinite 20s linear;
height: 25vmin;
pointer-events: none;
}
.App-header {
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
}
.App-link {
color: #61dafb;
}
img {
width: 250px;
height: 250px;
}
`;
export default GlobalStyle;
ThemeProvider
μμchildren
μ λ§λ€μ΄μprops
νμμΌλ‘ ν μ€νΈλ₯Ό μ λ ₯ν μ μκ²λ νλ€.toggle
ν¨μλ₯Ό λ§λ€μ΄App.tsx
μ μλ λ²νΌμ ν΄λ¦ν μ ν λ§κ° λ°κΎΈλ κ²μ κ°λ₯νκ² λ§λ λ€.
import * as React from "react";
import styled, { ThemeProvider } from "styled-components";
import { backgroundColor, textColor } from "./theme";
const ThemeToggleContext: any = React.createContext(null);
export const useTheme = () => React.useContext(ThemeToggleContext);
interface Type {
children: JSX.Element
}
export const MyThemeProvider = ({ children }: Type) => {
const [themeState, setThemeState] = React.useState({
mode: "light"
});
const Wrapper = styled.div`
background-color: ${backgroundColor};
color: ${textColor};
`;
const toggle = () => {
const mode = themeState.mode === "light" ? `dark` : `light`;
setThemeState({ mode: mode });
};
return (
<ThemeToggleContext.Provider value={{ toggle: toggle }}>
<ThemeProvider theme={{ mode: themeState.mode }}>
<Wrapper>{children}</Wrapper>
</ThemeProvider>
</ThemeToggleContext.Provider>
);
};
export default ThemeProvider;
- ν
λ§κ° λ³κ²½λ λ
backgroundColor
μtextColor
,buttonBackgroundColor
,buttonTextColor
μ μλ£λ€μ μ λ ₯νλ€.
import theme from "styled-theming";
export const backgroundColor = theme("mode", {
light: "#fafafa",
dark: "#222"
});
export const textColor = theme("mode", {
light: "#000",
dark: "#fff"
});
export const buttonBackgroundColor = theme("mode", {
light: "#222",
dark: "#eee"
});
export const buttonTextColor = theme("mode", {
light: "#eee",
dark: "#222"
});