[ブログの作成]ダークモードの実装(typescript)
36849 ワード
🛠 開発環境:nextJS、typescript、emotionJS
超暗モード機能を実現
ダークモード機能が適用されます.
スタイルを
💄 光源モード/暗いモードスタイルの指定
まず、光源モードと暗いモードスタイルを指定します.この場合、
mainFont
、subFont
等の対象のキー値は同一でなければならない.styles.theme.tsx
export const lightTheme = {
MAIN: "#6868AD",
SUB: "#dbd7ff",
BACKGROUND: "#fdfdff",
SUBBACKGROUND: "rgb(242, 240, 253)",
}
export const darkTheme : Theme = {
MAIN: "#dbd7ff",
SUB: "#6868AD",
BACKGROUND: "#202124",
SUBBACKGROUND: "#30373e",
}
次にタイプを指定します.typeof
を使用する場合は、指定されたオブジェクト(lightTheme)のpropertyタイプを参照してタイプを宣言できます.let s = "hello";
let n: typeof s;
アプリケーションexport type Theme = typeof lightTheme;
すべてのダークモード状態管理-themeProvider
ページを移動するときに適切なトピックを維持するために、
theme provider
およびtheme context
を使用して暗いモード状態管理を行います.通常、reactでは、データは親から子供へ
props
を介して伝達される.しかし、親から子へではなく曾祖から曾孫へと伝えられると、過程は非常に面倒になる.この場合contextを用いて,各フェーズでpropsを渡す必要がなく,グローバル範囲で値を共有できる.Appの一番上にあるThemeContextサブコンポーネントがContextを介してトピックにアクセスできるようにProviderを追加します.React.createContext
const MyContext = React.createContext(defaultValue);
ここで、defalutvalue
は、素子が適切なprovider
を見つけられない場合に用いられる値である.アプリケーション
//타입 지정
interface ContextProps {
theme: Theme
toggleTheme: () => void
}
//객체 생성
export const ThemeContext = createContext<ContextProps>({
theme: lightTheme,
toggleTheme: () => {
return null
},
})
Context.Provider
ThemeContextオブジェクトの作成が完了しました.Contextオブジェクトを購読するコンポーネントがContext Providerから現在の値を読み込むようになりました.
<MyContext.Provider value={/* 어떤 값 */}>
providerは、コンテキストの変化を通知し、value propを受信してサブコンポーネントに渡す責任を負います.したがって、プロバイダの値が変更されると、サブスクリプションコンテキストのすべてのコンポーネントが再レンダリングされます.アプリケーション
// _app.tsx
import type { AppProps } from 'next/app';
import React, { createContext } from 'react';
import { Global } from '@emotion/react';
import { GlobalStyle } from '@styles/global-styles';
import { lightTheme, darkTheme, Theme } from '@styles/theme';
import { useDarkMode } from '@hooks/useDarkMode';
import DarkModeToggle from '@components/Home/DarkModetoggle';
interface ContextProps {
theme: Theme
toggleTheme: () => void
}
//contextX객체 생성
export const ThemeContext = createContext<ContextProps>({
//테마와 테마를 변경하는 함수
theme: lightTheme,
toggleTheme: () => {
return null
},
})
//useDarkMode hook을 통해 theme과 toggleTheme return;
const { theme, toggleTheme } = useDarkMode();
function MyApp({ Component, pageProps }: AppProps) {
const { theme, toggleTheme } = useDarkMode()
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>8
<Global
styles={GlobalStyle(theme === lightTheme ? lightTheme : darkTheme)}
/>
<Component {...pageProps} />
<DarkModeToggle />
</ThemeContext.Provider>
)
}
export default MyApp
暗いモードの状態値を保存する:localStorageとnextJS
// useDarkMode.ts
import { useEffect, useState } from "react";
import { lightTheme, darkTheme, Theme } from "../styles/theme";
export const useDarkMode = () => {
const [theme, setTheme] = useState<Theme>(lightTheme);
const setMode = (mode: Theme) => {
mode === lightTheme
? window.localStorage.setItem("theme", "light")
: window.localStorage.setItem("theme", "dark");
setTheme(mode);
};
const toggleTheme = () => {
theme === lightTheme ? setMode(darkTheme) : setMode(lightTheme);
};
useEffect(() => {
const localTheme = window.localStorage.getItem("theme");
if (localTheme !== null) {
if (localTheme === "dark") {
setTheme(darkTheme);
} else {
setTheme(lightTheme);
}
}
}, []);
return { theme, toggleTheme };
};
現在のトピック(theme
)と、トピックを変更する関数(toggleTheme
)を返すhookが生成される.nextJSはサーバ側レンダリングであるため、window
、localStorage
、alert
などに直接近づくとundefined
が吐き出される.ただし、レンダリング後に実行されるuseEffect
の性質を利用すれば、localStorage
を使用することができる.デフォルトでは、localStorage
にlightトピックが保存され、マウスをクリックするたびにトピックが変更されます.その後、ユーザがページを移動またはリフレッシュするときも、localStorage
を参照してトピックを保持する.暗いモードを切り替え
import LightModeIcon from '@mui/icons-material/LightMode';
import DarkModeIcon from '@mui/icons-material/DarkMode';
import styled from '@emotion/styled';
import React, { ReactElement, useContext } from 'react';
import { ThemeContext } from '@pages/_app';
import { lightTheme, Theme } from '@styles/theme';
import { MEDIA_QUERY_END_POINT } from '@constants/.';
interface ToggleProps {
theme: Theme;
}
export default function DarkModeToggle(): ReactElement {
const { theme, toggleTheme } = useContext(ThemeContext);
return (
<ToggleButton onClick={toggleTheme} theme={theme}>
{theme === lightTheme ? (
<>
<Emoji>
<DarkModeIcon aria-label="darkMoon" />
</Emoji>
<ModeContent>다크 모드</ModeContent>
</>
) : (
<>
<Emoji>
<LightModeIcon aria-label="lightSun" />
</Emoji>
<ModeContent>라이트 모드</ModeContent>
</>
)}
</ToggleButton>
);
}
useContext
によってProvider
に渡されたトピックを購読し、トピックを切り替えます.次に、トピックを変更するToggleTheme関数をbutton構成部品のonClickイベントに接続します.ダークモード適用方式1。global
ダークモードの適用方法は2種類あります.1つ目はglobalstyleを用いてappでスタイルを下げる方法です.
//global-style.ts
import { css } from "@emotion/react";
import { Theme } from "../styles/theme";
export const GlobalStyle = (props: Theme) =>
css`
body {
background: ${props.BACKGROUND};
color: ${props.MAIN_FONT};
}
`;
//app.ts
import type { AppProps } from "next/app"
import React, { createContext } from "react"
import { Global } from "@emotion/react"
import { GlobalStyle } from "@styles/global-styles"
import { lightTheme, darkTheme, Theme } from "@styles/theme"
import { useDarkMode } from "@hooks/useDarkMode"
import DarkModeToggle from "@components/Home/DarkModetoggle"
export const ThemeContext = createContext<ContextProps>({
theme: lightTheme,
toggleTheme: () => {
return null
},
})
function MyApp({ Component, pageProps }: AppProps) {
const { theme, toggleTheme } = useDarkMode()
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>8
<Global
styles={GlobalStyle(theme === lightTheme ? lightTheme : darkTheme)}
/>
<Component {...pageProps} />
<DarkModeToggle />
</ThemeContext.Provider>
)
}
export default MyApp
ダークモード適用方式2。useContextを使用して各構成部品に適用
2つ目の方法は、useContextを使用して各コンポーネントからcontextを購読することです.チームプロジェクトにはエレメントやスタイル指定変数がたくさんあるので、2つ目の方法を選択しました.
import { useContext } from 'react';
import { Theme } from '@styles/theme';
import { ThemeContext } from '@pages/_app';
interface ThemeProps {
theme: Theme;
}
export const ListCard = () => {
const { theme } = useContext(ThemeContext);
return (
<Card theme={theme}/>
)
const Card = styled.article<ThemeProps>`
background: ${({ theme }) => theme.CARD_BACKGROUND};
}
`;
}
📸 機能実装画面
注:リンク1
メモリンク2
Reference
この問題について([ブログの作成]ダークモードの実装(typescript)), 我々は、より多くの情報をここで見つけました https://velog.io/@ongddree/블로그만들기-다크모드-구현テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol