SSR React 애플리케이션에서 테마 설정
밝은 테마, 어두운 테마, 시스템 기반 테마를 손쉽게 전환하면서 귀하의 선호도에 맞춰 원활하게 조정되는 웹사이트를 방문한다고 상상해 보십시오.
이 기사에서는 React를 사용한 SSR에 대한 시리즈를 이어갑니다. 기본 기사에서는 생산 준비가 완료된 구성을 살펴봤고, 고급 기술에서는 수화 오류와 같은 문제를 해결했습니다. 이제 SSR과 원활하게 통합되는 강력한 테마 지원을 구현하여 한 단계 더 발전하겠습니다.
목차
- 테마와 SSR
-
구현
- 종속성 설치
- 서버 빌드에 쿠키 추가
- 서버에 테마 적용
- 클라이언트에서 테마 처리
- 결론
테마 및 SSR
주요 이슈는 잘못된 테마의 초기 플래시(FOIT)입니다.
기본적으로 테마는 CSS 변수를 변경하는 것입니다. 대부분의 경우 세 가지 테마로 작업하게 됩니다.
- Light: CSS 변수의 기본 세트
- 어둡게: 태그의 클래스는 dark입니다.
- 시스템: (선호-색상-구성: 어두움)을 사용하여 사용자의 시스템 기본 설정에 따라 자동으로 전환합니다. 테마가 어둡거나 밝아야 하는지 결정하기 위한 미디어 쿼리입니다.
기본적으로 서버는 밝은 테마로 HTML을 렌더링하여 브라우저로 보냅니다. 사용자가 어두운 테마를 선호하는 경우 첫 번째 페이지 로드 시 시각적인 테마 변경이 표시되어 사용자 경험을 방해합니다.
이 문제를 해결하는 두 가지 주요 방법은 다음과 같습니다.
- <스크립트> 추가 서버의 HTML에 태그를 지정하고 클라이언트에서 클래스를 동적으로 설정합니다.
- 쿠키를 사용하여 사용자의 테마 기본 설정을 저장하고 서버에 클래스를 설정합니다.
첫 번째 해결 방법은 다음 테마 패키지의 작동 방식입니다(2025년 1월). 이 기사에서는 SSR 애플리케이션에서 원활한 테마 처리를 보장하기 위해 쿠키 기반 접근 방식을 구현합니다.
구현
테마를 구현하려면 다음 두 가지 쿠키를 사용합니다.
- serverTheme - 태그.
- clientTheme - 수화 오류를 처리하는 데 사용됩니다.
클라이언트는 항상 두 쿠키를 모두 설정하여 서버가 다음 요청 시 적절한 테마를 올바르게 렌더링할 수 있도록 합니다.
이 가이드는 이전 기사인 생산 가능한 SSR React 애플리케이션 구축에서 소개된 개념을 기반으로 하며, 해당 기사는 하단에 링크되어 있습니다. 단순화를 위해 공유 상수 및 유형은 여기에서 생성되지 않지만 예제 저장소에서 해당 구현을 찾을 수 있습니다.
종속성 설치
쿠키 처리에 필요한 패키지를 설치합니다.
pnpm add cookie js-cookie
js-cookie 설치 유형:
pnpm add -D @types/js-cookie
앱에서 반응 라우터를 사용하지 않는 경우 쿠키 패키지를 devDependency로 사용할 수 있습니다.
서버 빌드에 쿠키 추가
tsup 구성 파일 업데이트:
// ./tsup.config.ts import { defineConfig } from 'tsup' export default defineConfig({ entry: ['server'], outDir: 'dist/server', target: 'node22', format: ['cjs'], clean: true, minify: true, external: ['lightningcss', 'esbuild', 'vite'], noExternal: [ 'express', 'sirv', 'compression', 'cookie', // Include the cookie in the server build ], })
서버에 테마 적용
테마 상수 정의
// ./server/constants.ts export const CLIENT_THEME_COOKIE_KEY = 'clientTheme' export const SERVER_THEME_COOKIE_KEY = 'serverTheme' export enum Theme { Light = 'light', Dark = 'dark', System = 'system' }
태그에 테마 클래스 적용
올바른 테마 클래스를 serverTheme 쿠키를 기반으로 하는 태그:
// ./server/lib/applyServerTheme.ts import { parse } from 'cookie' import { Request } from 'express' import { SERVER_THEME_COOKIE_KEY, Theme } from '../constants' export function applyServerTheme(req: Request, html: string): string { const cookies = parse(req.headers.cookie || '') const theme = cookies?.[SERVER_THEME_COOKIE_KEY] if (theme === Theme.Dark) { return html.replace('<html lang="en">', `<html lang="en"> <h4> Retrieve the Client Theme Cookie </h4> <p>Create a utility function to retrieve the clientTheme cookie<br> </p> <pre class="brush:php;toolbar:false">// ./server/getClientTheme.ts import { parse } from 'cookie' import { Request } from 'express' import { CLIENT_THEME_COOKIE_KEY, Theme } from '../constants' export function getClientTheme(req: Request) { const cookies = parse(req.headers.cookie || '') return cookies?.[CLIENT_THEME_COOKIE_KEY] as Theme | undefined }
테마를 위한 서버 구성 업데이트
개발 구성:
// ./server/dev.ts import fs from 'fs' import path from 'path' import { Application } from 'express' import { HTML_KEY } from './constants' import { applyServerTheme } from './lib/applyServerTheme' import { getClientTheme } from './lib/getClientTheme' const HTML_PATH = path.resolve(process.cwd(), 'index.html') const ENTRY_SERVER_PATH = path.resolve(process.cwd(), 'src/entry-server.tsx') export async function setupDev(app: Application) { const vite = await ( await import('vite') ).createServer({ root: process.cwd(), server: { middlewareMode: true }, appType: 'custom', }) app.use(vite.middlewares) app.get('*', async (req, res, next) => { try { let html = fs.readFileSync(HTML_PATH, 'utf-8') html = await vite.transformIndexHtml(req.originalUrl, html) const { render } = await vite.ssrLoadModule(ENTRY_SERVER_PATH) // send Client Theme from cookie to render const appHtml = await render(getClientTheme(req)) // Apply Server theme on template html html = applyServerTheme(req, html) html = html.replace(HTML_KEY, appHtml) res.status(200).set({ 'Content-Type': 'text/html' }).end(html) } catch (e) { vite.ssrFixStacktrace(e as Error) console.error((e as Error).stack) next(e) } }) }
제작 구성:
// ./server/prod.ts import fs from 'fs' import path from 'path' import compression from 'compression' import { Application } from 'express' import sirv from 'sirv' import { HTML_KEY } from './constants' import { applyServerTheme } from './lib/applyServerTheme' import { getClientTheme } from './lib/getClientTheme' const CLIENT_PATH = path.resolve(process.cwd(), 'dist/client') const HTML_PATH = path.resolve(process.cwd(), 'dist/client/index.html') const ENTRY_SERVER_PATH = path.resolve(process.cwd(), 'dist/ssr/entry-server.js') export async function setupProd(app: Application) { app.use(compression()) app.use(sirv(CLIENT_PATH, { extensions: [] })) app.get('*', async (req, res, next) => { try { let html = fs.readFileSync(HTML_PATH, 'utf-8') const { render } = await import(ENTRY_SERVER_PATH) // send Client Theme from cookie to render const appHtml = await render(getClientTheme(req)) // Apply Server theme on template html html = applyServerTheme(req, html) html = html.replace(HTML_KEY, appHtml) res.status(200).set({ 'Content-Type': 'text/html' }).end(html) } catch (e) { console.error((e as Error).stack) next(e) } }) }
클라이언트에서 테마 처리
상수 정의
클라이언트용으로 상수를 복제하거나 공유 폴더로 이동
// ./src/constants.ts export const SSR = import.meta.env.SSR export const CLIENT_THEME_COOKIE_KEY = 'clientTheme' export const SERVER_THEME_COOKIE_KEY = 'serverTheme' export enum Theme { Light = 'light', Dark = 'dark', System = 'system', }
테마 컨텍스트 생성
테마 상태를 관리하고 테마 관리 방법을 제공하기 위해 React 컨텍스트를 설정합니다.
// ./src/theme/context.ts import { createContext, useContext } from 'react' import { Theme } from '../constants' export type ThemeContextState = { theme: Theme setTheme: (theme: Theme) => void } export const ThemeContext = createContext<ThemeContextState>({ theme: Theme.System, setTheme: () => null, }) export const useThemeContext = () => useContext(ThemeContext)
테마 유틸리티 구현
// ./src/theme/lib.ts import Cookies from 'js-cookie' import { CLIENT_THEME_COOKIE_KEY, SERVER_THEME_COOKIE_KEY, SSR, Theme } from '../constants' // Resolve the system theme using the `prefers-color-scheme` media query export function resolveSystemTheme() { if (SSR) return Theme.Light return window.matchMedia('(prefers-color-scheme: dark)').matches ? Theme.Dark : Theme.Light } // Update the theme cookies and set appropriate class to <html> export function updateTheme(theme: Theme) { if (SSR) return const resolvedTheme = theme === Theme.System ? resolveSystemTheme() : theme Cookies.set(CLIENT_THEME_COOKIE_KEY, theme) Cookies.set(SERVER_THEME_COOKIE_KEY, resolvedTheme) window.document.documentElement.classList.toggle('dark', resolvedTheme === Theme.Dark) } // Get the default theme from cookies export function getDefaultTheme(): Theme { if (SSR) return Theme.System const theme = (Cookies.get(CLIENT_THEME_COOKIE_KEY) as Theme) || Theme.System updateTheme(theme) return theme }
테마 공급자 생성
// ./src/theme/Provider.tsx import { PropsWithChildren, useState } from 'react' import { Theme } from '../constants' import { ThemeContext } from './context' import { getDefaultTheme, updateTheme } from './lib' type Props = PropsWithChildren & { defaultTheme?: Theme // Handle theme for SSR } export function ThemeProvider({ children, defaultTheme }: Props) { const [theme, setTheme] = useState<Theme>(defaultTheme || getDefaultTheme()) const handleSetTheme = (theme: Theme) => { setTheme(theme) updateTheme(theme) } return <ThemeContext value={{ theme, setTheme: handleSetTheme }}>{children}</ThemeContext> }
// ./src/theme/index.ts export { ThemeProvider } from './Provider' export { useThemeContext } from './context'
구성 요소에서 테마 컨텍스트 사용
// ./src/App.tsx import reactLogo from './assets/react.svg' import viteLogo from '/vite.svg' import Card from './Card' import { Theme } from './constants' import { ThemeProvider } from './theme' import './App.css' // Theme from Server Entry type AppProps = { theme?: Theme } function App({ theme }: AppProps) { return ( <ThemeProvider defaultTheme={theme}> <div> <a href="https://vite.dev" target="_blank" rel="noreferrer"> <img src={viteLogo} className="logo" alt="Vite logo" /> </a> <a href="https://react.dev" target="_blank" rel="noreferrer"> <img src={reactLogo} className="logo react" alt="React logo" /> </a> </div> <h1>Vite + React</h1> <Card /> <p className="read-the-docs">Click on the Vite and React logos to learn more</p> </ThemeProvider> ) } export default App
카드 구성요소 생성
// ./src/Card.tsx import { useState } from 'react' import { Theme } from './constants' import { useThemeContext } from './theme' function Card() { const { theme, setTheme } = useThemeContext() const [count, setCount] = useState(0) return ( <div className='card'> <button onClick={() => setCount((count) => count + 1)}>count is {count}</button> <p> Edit <code>src/App.tsx</code> and save to test HMR </p> <div> Themes:{' '} <select value={theme} onChange={(event) => setTheme(event.target.value as Theme)}> <option value={Theme.System}>System</option> <option value={Theme.Light}>Light</option> <option value={Theme.Dark}>Dark</option> </select> </div> </div> ) } export default Card
수화 오류 해결
테마를 서버 렌더링 메소드에 전달하여 서버 생성 HTML이 클라이언트측 렌더링과 일치하는지 확인하세요.
import { renderToString } from 'react-dom/server' import App from './App' import { Theme } from './constants' export function render(theme: Theme) { return renderToString(<App theme={theme} />) }
스타일 추가
:root { color: #242424; background-color: rgba(255, 255, 255, 0.87); } :root.dark { color: rgba(255, 255, 255, 0.87); background-color: #242424; }
결론
이 기사에서는 SSR React 애플리케이션에서 원활한 테마를 구현하는 문제를 다루었습니다. 쿠키를 사용하고 클라이언트 측 논리와 서버 측 논리를 통합함으로써 수화 오류나 사용자 경험 중단 없이 밝은 테마, 어두운 테마, 시스템 기반 테마를 지원하는 강력한 시스템을 만들었습니다.
코드 탐색
- 예: 반응-ssr-테마-예
- SSR로 착륙: 전문 착륙
관련 기사
이것은 React를 사용한 SSR 시리즈의 일부입니다. 더 많은 기사를 기대해주세요!
- 생산 준비가 완료된 SSR React 애플리케이션 구축
- 스트리밍 및 동적 데이터를 사용한 고급 React SSR 기술
- SSR React 애플리케이션에서 테마 설정
연결 상태 유지
저는 항상 피드백, 협업 또는 기술 아이디어 논의에 열려 있습니다. 언제든지 연락주세요!
- 포트폴리오: maxh1t.xyz
- 이메일: m4xh17@gmail.com
위 내용은 SSR React 애플리케이션에서 테마 설정의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

Video Face Swap
완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

Python은 부드러운 학습 곡선과 간결한 구문으로 초보자에게 더 적합합니다. JavaScript는 가파른 학습 곡선과 유연한 구문으로 프론트 엔드 개발에 적합합니다. 1. Python Syntax는 직관적이며 데이터 과학 및 백엔드 개발에 적합합니다. 2. JavaScript는 유연하며 프론트 엔드 및 서버 측 프로그래밍에서 널리 사용됩니다.

C/C에서 JavaScript로 전환하려면 동적 타이핑, 쓰레기 수집 및 비동기 프로그래밍으로 적응해야합니다. 1) C/C는 수동 메모리 관리가 필요한 정적으로 입력 한 언어이며 JavaScript는 동적으로 입력하고 쓰레기 수집이 자동으로 처리됩니다. 2) C/C를 기계 코드로 컴파일 해야하는 반면 JavaScript는 해석 된 언어입니다. 3) JavaScript는 폐쇄, 프로토 타입 체인 및 약속과 같은 개념을 소개하여 유연성과 비동기 프로그래밍 기능을 향상시킵니다.

웹 개발에서 JavaScript의 주요 용도에는 클라이언트 상호 작용, 양식 검증 및 비동기 통신이 포함됩니다. 1) DOM 운영을 통한 동적 컨텐츠 업데이트 및 사용자 상호 작용; 2) 사용자가 사용자 경험을 향상시키기 위해 데이터를 제출하기 전에 클라이언트 확인이 수행됩니다. 3) 서버와의 진실한 통신은 Ajax 기술을 통해 달성됩니다.

실제 세계에서 JavaScript의 응용 프로그램에는 프론트 엔드 및 백엔드 개발이 포함됩니다. 1) DOM 운영 및 이벤트 처리와 관련된 TODO 목록 응용 프로그램을 구축하여 프론트 엔드 애플리케이션을 표시합니다. 2) Node.js를 통해 RESTFULAPI를 구축하고 Express를 통해 백엔드 응용 프로그램을 시연하십시오.

보다 효율적인 코드를 작성하고 성능 병목 현상 및 최적화 전략을 이해하는 데 도움이되기 때문에 JavaScript 엔진이 내부적으로 작동하는 방식을 이해하는 것은 개발자에게 중요합니다. 1) 엔진의 워크 플로에는 구문 분석, 컴파일 및 실행; 2) 실행 프로세스 중에 엔진은 인라인 캐시 및 숨겨진 클래스와 같은 동적 최적화를 수행합니다. 3) 모범 사례에는 글로벌 변수를 피하고 루프 최적화, Const 및 Lets 사용 및 과도한 폐쇄 사용을 피하는 것이 포함됩니다.

Python과 JavaScript는 커뮤니티, 라이브러리 및 리소스 측면에서 고유 한 장점과 단점이 있습니다. 1) Python 커뮤니티는 친절하고 초보자에게 적합하지만 프론트 엔드 개발 리소스는 JavaScript만큼 풍부하지 않습니다. 2) Python은 데이터 과학 및 기계 학습 라이브러리에서 강력하며 JavaScript는 프론트 엔드 개발 라이브러리 및 프레임 워크에서 더 좋습니다. 3) 둘 다 풍부한 학습 리소스를 가지고 있지만 Python은 공식 문서로 시작하는 데 적합하지만 JavaScript는 MDNWebDocs에서 더 좋습니다. 선택은 프로젝트 요구와 개인적인 이익을 기반으로해야합니다.

개발 환경에서 Python과 JavaScript의 선택이 모두 중요합니다. 1) Python의 개발 환경에는 Pycharm, Jupyternotebook 및 Anaconda가 포함되어 있으며 데이터 과학 및 빠른 프로토 타이핑에 적합합니다. 2) JavaScript의 개발 환경에는 Node.js, VScode 및 Webpack이 포함되어 있으며 프론트 엔드 및 백엔드 개발에 적합합니다. 프로젝트 요구에 따라 올바른 도구를 선택하면 개발 효율성과 프로젝트 성공률이 향상 될 수 있습니다.

C와 C는 주로 통역사와 JIT 컴파일러를 구현하는 데 사용되는 JavaScript 엔진에서 중요한 역할을합니다. 1) C는 JavaScript 소스 코드를 구문 분석하고 추상 구문 트리를 생성하는 데 사용됩니다. 2) C는 바이트 코드 생성 및 실행을 담당합니다. 3) C는 JIT 컴파일러를 구현하고 런타임에 핫스팟 코드를 최적화하고 컴파일하며 JavaScript의 실행 효율을 크게 향상시킵니다.
