0. shadcn-ui로 다크모드
shadcnui로 다크모드를 쉽게 개발 가능합니다.
'use client'
import * as React from 'react'
import { ThemeProvider as NextThemesProvider } from 'next-themes'
export function ThemeProvider({
children,
...props
}: React.ComponentProps<typeof NextThemesProvider>) {
return <NextThemesProvider {...props}>{children}</NextThemesProvider>
}
export default async function RootLayout({
children,
}: Readonly<{
children: React.ReactNode
}>) {
const currentUser = await getCurrentUser()
return (
<html lang='ko' >
<body className={spoqa.className}>
<main className=''>
<ThemeProvider
attribute='class'
defaultTheme='system'
enableSystem
disableTransitionOnChange
storageKey='theme-preference' // 테마 설정을 저장할 키 추가
enableColorScheme={false} // color-scheme 스타일 비활성화
>
{children}
</main>
</body>
</html>
)
}
위와같이 코드를 작성후
import { useTheme } from 'next-themes'
const { setTheme } = useTheme()
<button onClick={() => setTheme('light')}>
Light
</button >
<button onClick={() => setTheme('dark')}>
Dark
</button >
<button onClick={() => setTheme('system')}>
System
</button >
이렇게 사용해주면 끝납니다.
✨당연히 global.css에서 라이트/다크 모드에 대한 스타일처리를 해줘야하긴 합니다.
잘 작동합니다.
1. HydrationWarning
ThemaProvider은 서버컴포넌트 구성요소가 아니라 클라이언트 구성요소입니다.
초기 서버컴포넌트는 아무런 값도 받아오지 못한 상태이고, html 직렬화가 이루어진 다음에야 테마 값을 받아오기 때문에 하이드레이션 에러 경고문이 나옵니다.
이러한 에러를 처리해주기 위해서
shadcnUI측에서 제시하고 있는 방안은 다음과 같습니다.
<html lang='ko' suppressHydrationWarning> // suppressHydrationWarning 추가
<body className={spoqa.className}>
<main className=''>
<ThemeProvider
attribute='class'
defaultTheme='system'
enableSystem
disableTransitionOnChange
storageKey='theme-preference' // 테마 설정을 저장할 키 추가
enableColorScheme={false} // color-scheme 스타일 비활성화
>
{children}
</main>
</body>
</html>
`suppressHydrationWarning` 를 RootLayout에 추가해주는 방법입니다.
suppressHydrationWarning를 기입해주게 되면 하이드레이션 에러 경고문을 끄게됩니다.
하지만 여기서 의문이듭니다.
루트레이아웃에 `suppressHydrationWarning` 를 적어버리면 하위 컴포넌트들은 모두 영향을 받는건데, 개발자의 실수로 하이드레이션 이슈가 발생했는데 그걸 못잡아내는거 아닐까?
다행히 이 속성은 `한 단계 깊이`에만 적용되므로 다른 요소의 수화 경고를 차단하지 않는다고 합니다.
Should I set suppressHydrationWarning when using ThemeProvider · shadcn-ui ui · Discussion #6449
<html lang='ko' suppressHydrationWarning> ... <ThemeProvider> ... </<ThemeProvider> </html> "If we use it in the root layout like this, wouldn't it turn off hydration warnings for all child compone...
github.com
3. 더 나아가서 ‘한 단계 깊이’란?
코드 예시입니다.
<div suppressHydrationWarning> // 첫 번째 레벨 (여기가 한 단계 깊이)
<span>시간: {new Date().toLocaleString()}</span> // 이 요소의 hydration 경고는 억제됨
<div> // 두 번째 레벨
<p>{new Date().toLocaleString()}</p> // 이 요소는 hydration 경고가 발생할 수 있음
</div>
</div>
4. 정리
정리하자면 이렇습니다.
- `suppressHydrationWarning`이 적용된 요소의 직접적인 자식 요소들에만 영향을 미침
- 손자 요소들(더 깊은 레벨)에는 영향을 주지 않음
'기록' 카테고리의 다른 글
supabase,zustand로 user 로그인 처리한거를 react-query로 변경 (0) | 2025.01.23 |
---|---|
'Set'을 활용해서 기존 배열중에서 삭제된 배열값 구하기 (0) | 2024.11.19 |
'parameter' , 'argument' 정의 (2) | 2024.11.18 |
react, nestjs에서 소셜 로그인 구현하기 (0) | 2024.08.19 |