[react.js]ダークモード(Emotion.js+Next.js+Type Script)
23156 ワード
https://velog.io/@ongdree/ブログの作成-暗いモード-実装
他のプロジェクトでの実装をレビューする投稿を参照してください.
🎯 TL;DR
プロジェクトの開始後に暗いモードを迅速に実施することをお勧めします.(コツ🍯)
タイトルでは、ライトモード/キーの切り替えでトピックを変更します.
ページを移動、リフレッシュしても、アプリケーションのトピックは保持されます.(Context API + localStorage)
1𗞚テーマの色の指定 // styles/theme.ts
export const lightTheme = {
MAIN: 'black',
SUB: 'white',
BACKGROUND: '#fdfdff',
};
export const darkTheme = {
MAIN: 'white',
SUB: 'black',
BACKGROUND: '#202124',
};
export type ColorTheme = typeof lightTheme;
// styles/theme.ts
export const lightTheme = {
MAIN: 'black',
SUB: 'white',
BACKGROUND: '#fdfdff',
};
export const darkTheme = {
MAIN: 'white',
SUB: 'black',
BACKGROUND: '#202124',
};
export type ColorTheme = typeof lightTheme;
MAIN
とSUB
は文字の色を指定し、BACKGROUND
は背景の色を指定します.(より多くの色が必要な場合は追加!)ColorTheme typeを
typeof
でエクスポートします.2▼UseDarkMode()を実施する
Next.jsでは、レンダリング前に
localStorage
、window
などに近づくとエラーが発生します.したがって、useEffect
の内部でwindow.localStorage.getItem('theme')
によってトピックのリフレッシュまたは初回レンダリングが決定される.(default値はlightTheme
です.)初めて
localStorage.setItem
を行ったのは、光線モード->ダークモードが始まったときです.// hooks/useDarkMode.ts
import { useEffect, useState } from 'react';
import { lightTheme, darkTheme, ColorTheme } from '../styles/theme';
export const useDarkMode = () => {
// 1. 초기 colorTheme은 lightTheme를 가진다.
const [colorTheme, setColorTheme] = useState<ColorTheme>(lightTheme);
// 4. state의 값도 변경 + local 저장 값도 변경
const setMode = (mode: ColorTheme) => {
mode === lightTheme
? window.localStorage.setItem('theme', 'light')
: window.localStorage.setItem('theme', 'dark');
setColorTheme(mode);
};
// 3. 사용자가 toggleColorTheme을 하면 setMode를 통해 기존의 colorTheme과 반대 값을 저장한다.
const toggleColorTheme = () => {
colorTheme === lightTheme ? setMode(darkTheme) : setMode(lightTheme);
};
// 2. 마운트 되면 localStorage에 'theme'이 있는지 찾는다.
// - 새로고침시 다크모드/라이트모드 바로 적용
// - 페이지 로드가 처음이면 이 과정은 무시된다
useEffect(() => {
const localTheme = window.localStorage.getItem('theme');
if (localTheme !== null) { // localTheme이 존재한다면
if (localTheme === 'dark') {
setColorTheme(darkTheme);
} else {
setColorTheme(lightTheme);
}
}
}, []);
return { colorTheme, toggleColorTheme };
};
3朕暗モード状態管理
Context APIを使用して、propsの転送を続行しないようにします.ThemeContext.Provider
では、サブコンポーネントがContextを介してトピックにアクセスし、ページを移動するときにトピックを保持できるようにします.
Next.jsでは最上階が_app
なので、ここで設定します.// pages/_app.tsx
import React, { createContext } from 'react';
import type { AppProps } from 'next/app';
import { Global } from '@emotion/react';
import { lightTheme, darkTheme, ColorTheme } from '../styles/theme';
// createContext 타입지정
interface ContextProps {
colorTheme: ColorTheme;
toggleColorTheme: () => void;
}
// Context 생성
export const ThemeContext = createContext<ContextProps>({
colorTheme: lightTheme, // 초기 값으로 lightTheme를 넣어줍니다.
toggleColorTheme: () => { // light || dark mode를 토글합니다.
return null
},
})
function MyApp({ Component, pageProps }: AppProps) {
// ❗️useDarkMode hook을 통해 theme과 toggleTheme return;
const { theme, toggleTheme } = useDarkMode();
return (
// Provider은 context의 변화를 알리는 역할을 합니다.
// toggleTheme를 통해 theme이 변경되면 하위 컴포넌트들은 모두 리렌더링됩니다.
<ThemeContext.Provider value={{ theme, toggleTheme }}>
<Component {...pageProps} />
</ThemeContext.Provider>
)
}
export default MyApp
4πダークモード使用と切り替えボタン
// pages/_app.tsx
import React, { createContext } from 'react';
import type { AppProps } from 'next/app';
import { Global } from '@emotion/react';
import { lightTheme, darkTheme, ColorTheme } from '../styles/theme';
// createContext 타입지정
interface ContextProps {
colorTheme: ColorTheme;
toggleColorTheme: () => void;
}
// Context 생성
export const ThemeContext = createContext<ContextProps>({
colorTheme: lightTheme, // 초기 값으로 lightTheme를 넣어줍니다.
toggleColorTheme: () => { // light || dark mode를 토글합니다.
return null
},
})
function MyApp({ Component, pageProps }: AppProps) {
// ❗️useDarkMode hook을 통해 theme과 toggleTheme return;
const { theme, toggleTheme } = useDarkMode();
return (
// Provider은 context의 변화를 알리는 역할을 합니다.
// toggleTheme를 통해 theme이 변경되면 하위 컴포넌트들은 모두 리렌더링됩니다.
<ThemeContext.Provider value={{ theme, toggleTheme }}>
<Component {...pageProps} />
</ThemeContext.Provider>
)
}
export default MyApp
useDarkMode
サブスクリプションを使用して、ThemeContext
によって作成され、colorTheme
の~toggleColorTheme
およびuseContext
に伝播する.toggleColorTheme
を起動するには、ボタンをクリックします.cssは、導入された
colorTheme
によって適用される.// components/Header/HeaderBtns/DarkModeToggle/index.tsx
import React, { ReactElement, useContext } from 'react';
import { ThemeContext } from '../../../../pages/_app';
import styled from '@emotion/styled';
import { lightTheme, ColorTheme } from '../../../../styles/theme';
interface ToggleProps {
colorTheme: ColorTheme;
}
const DarkModeToggle = () => {
// 1. useContext를 통해서 colorTheme, toggleColorTheme를 구독한다
const { colorTheme, toggleColorTheme } = useContext(ThemeContext);
return (
// 2. 버튼을 클릭하면 toggleColorTheme을 작동한다
<ToggleButton onClick={toggleColorTheme} colorTheme={colorTheme}>
{colorTheme === lightTheme ? '다크 모드' : '라이트 모드'}
</ToggleButton>
);
}
// 3. colorTheme을 prop으로 가져와 css를 적용한다.
const ToggleButton = styled('button')<ToggleProps>`
display: flex;
color: ${({ colorTheme }) => colorTheme.MAIN};
cursor: pointer;
background: ${({ colorTheme }) => colorTheme.BACKGROUND};
box-shadow: 3px 3px 10px rgb(0 0 0 / 20%);
&:hover {
filter: brightness(${({ colorTheme }) => (colorTheme === lightTheme ? '0.9' : '1.13')});
}
`;
export default DarkModeToggle;
Reference
この問題について([react.js]ダークモード(Emotion.js+Next.js+Type Script)), 我々は、より多くの情報をここで見つけました https://velog.io/@minbr0ther/React.js-다크모드-Emotion.js-Next.js-TypeScriptテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol