231009(์) ์ฑ์ฅ
๐ค ์ฑ์ฅ์ผ์ง 7.0
์ฑ
ํ๋ณตํ ์ด๊ธฐ์ฃผ์์(์จ์ธ ๋ค์ด์ด)
์ ๋ด์ฉ์ ์๊ทน๋ฐ์ ์์ํ๋ ์๋ฐํ ์ฑ์ฅ๊ธฐ๋ก
์ด์์๋ ๊ฝ๊ณผ ์ฃฝ์ ๊ฝ์ ์ด๋ป๊ฒ ๊ตฌ๋ณํ๋๊ฐ?
์ฑ์ฅํ๊ณ ์๋ ๊ฒ์ด ์ด์ ์๋ ๊ฒ์ด๋ค.
์๋ช ์ ์ ์ผํ ์ฆ๊ฑฐ๋ ์ฑ์ฅ์ด๋ค!
โ (7.0)<์์ ๊ฐํธ>
ํ์ธ๋ง ํ์ต๋ฒ
์ ์๊ฒ ๋๋งํผ, ์ฑ์ฅ์ผ์ง๋ ์ ๋ง ๊ทธ ๋ ์ ํค์๋ ์ค์ฌ์ผ๋ก ๊ฐ๋จํ๊ฒ ์ ๋ฆฌํ๋๋ก ํ๋ค.
next ์ปดํฌ๋ํธ ๊ตฌ์ฑํ๊ธฐ
์ด๋์ ๋ ํ๋ก์ ํธ ์์ ์ ์ฌ๋ฌ ์ธํ ์ ๋ง๋ฌด๋ฆฌํ๊ณ ์ปดํฌ๋ํธ ๊ตฌ์ฑ์ ํ๋ ค๋ ์๊ฐ๋ณด๋ค ๋ง์ ๊ณ ๋ฏผ์ด ํ์ํ๋ค. 13๋ฒ์ ๋ถํฐ๋ ์ปดํฌ๋ํธ ๋ณ๋ก ํด๋ผ์ด์ธํธ, ์๋ฒ ์ปดํฌ๋ํธ๋ฅผ ๋ถ๋ฆฌํด์ ์ฌ์ฉํ ์ ์๊ฒ ๋์๋ค. ๊ทธ๋์ ์ปดํฌ๋ํธ๋ฅผ ๊ตฌ์ฑํ ๋ ์ด๋ค ์ปดํฌ๋ํธ๋ฅผ ์ฌ์ฉํ ์ง ๊ณ ๋ฏผ์ด ํ์ํ๋ค. ๊ธฐ๋ณธ์ ์ผ๋ก๋ ์ต๋ํ SSG๋ก ๊ตฌ์ฑํ๊ณ ๊ทธ ๋ค์ ์ ์ ์์ ์ธํฐ๋ ์ ์ด ์๋ ๊ฒฝ์ฐ์๋ ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ, ๋ฐ์ดํฐ๊ฐ ์์ฃผ ๋ณ๊ฒฝ๋๋ ๊ฒฝ์ฐ์๋ SSR๋ก ๊ตฌ์ฑํ๊ธฐ๋ก ํ๋ค. ๋ฌผ๋ก ๊ทธ๋ผ์๋ ํท๊ฐ๋ฆฌ๋ ๋ถ๋ถ๋ค์ด ์กด์ฌํ๊ธฐ๋ ํ๋ค. ์๋ฅผ ๋ค์ด, ์๋ฒ์๊ฒ ์ด๋ฏธ์ง๋ค์ ๊ฐ์ ธ์์ ๊ทธ ์ด๋ฏธ์ง๋ฅผ ๋์ดํ๊ณ ๊ทธ ์ด๋ฏธ์ง๋ฅผ ์ ์ ๊ฐ ์ ํํด์ ์ด๋ค UI ๋ณ๊ฒฝ์ ์ค๋ค๊ณ ํด๋ณด์. ์ด ๊ฒฝ์ฐ์๋ ์ด๋ฏธ์ง๋ค์ ๊ฐ์ ธ์ค๋ ๋ถ๋ถ์ ์๋ฒ ์ปดํฌ๋ํธ๋ก ๋๊ณ , ์ ์ ๊ฐ ์ ํํ๋ ๋ถ๋ถ์ ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ๋ก ๋๋ ๊ฒ์ด ๋ง๋ ๊ฒ ๊ฐ๋ค.(์์ง ์ด ๋ถ๋ถ์ ์ ๋๋ก ๊ตฌํํด๋ณด์ง ์์์ ํ์คํ์ง๋ ์๋ค. ํด๋ด์ผ์๋ฏ..!)
next ์ ์ ์ ๋ธ๋ผ์ฐ์ ์ค์ ์ ๋ฐ๋ผ ๋คํฌ๋ชจ๋ ์ ์ฉํ๊ธฐ
ํ์ฌ ๋คํฌ๋ชจ๋ ์ ๋ฌด์ ๋คํฌ/๋ผ์ดํธ๋ฅผ ๋ณ๊ฒฝํ๋ ํ ๊ธํจ์๋ฅผ context API๋ก ๊ด๋ฆฌํ๊ณ ์๋ค. ์ฝ๋๋ ์๋์ ๊ฐ๋ค.
'use client';
import { createContext, useContext, useState } from 'react';
export const ThemeContext = createContext({});
export const ToggleThemeContext = createContext(() => {
console.error('Forgot to wrap component in `ThemeProvider`');
});
export const useTheme = () => {
return useContext(ThemeContext);
};
export const useToggleTheme = () => {
return useContext(ToggleThemeContext);
};
type Props = {
children: React.ReactNode;
};
export default function ThemeProvider({ children }: Props) {
// NOTE: ํ์ฌ ์ ์ ๋ธ๋ผ์ฐ์ ์ค์ ํ
๋ง๋ฅผ ๊ฐ์ ธ์จ๋ค.
const isBrowser = typeof window !== 'undefined';
const initialTheme =
isBrowser && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches
? 'dark'
: 'light';
const [theme, setTheme] = useState(initialTheme);
const toggleTheme = () => {
setTheme(theme === 'light' ? 'dark' : 'light');
};
return (
<ThemeContext.Provider value={theme}>
<ToggleThemeContext.Provider value={toggleTheme}>
<div className={theme}>{children}</div>
</ToggleThemeContext.Provider>
</ThemeContext.Provider>
);
}
๊ทธ๋ฐ๋ฐ ๋ฌธ์ ๋ ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ์ฌ๋ ์๋ฒ์์ ํ๋ฆฌ๋ ๋๋ง์ ํ๊ธฐ ๋๋ฌธ์ ๊ทธ ๋๋ window
๊ฐ์ฒด๊ฐ undefined์ธ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ค. ๊ทธ๋ฌ๋ ์ค next.js์์ ์ ๊ณตํ๋ dynamic
์ ์ด์ฉํ๋ฉด ํด๊ฒฐํ ์ ์๋ค๋ ๊ฒ์ ์๊ฒ ๋์๋ค. ์๋์ ๊ฐ์ด ์ฌ์ฉํ๋ฉด ๋๋ค. ์์ ์ฝ๋์์ ThemeProvider
๋ฅผ importํ ๋ dynamic
์ผ๋ก ๊ฐ์ธ์ฃผ๋ฉด ๋๋ค.
import dynamic from 'next/dynamic';
const ThemeProvider = dynamic(() => import('components/ThemeProvider'), { ssr: false });
์ด๋ ๊ฒ ๋๋ฉด ์๋ฒ์์ ํ๋ฆฌ๋ ๋๋ง์ด ๋์ง ์๊ณ ํด๋ผ์ด์ธํธ์์๋ง ๋ ๋๋ง์ด ๋๊ธฐ ๋๋ฌธ์ window
๊ฐ์ฒด๊ฐ undefined๊ฐ ๋์ง ์๋๋ค.
๊ทธ๋ฐ๋ฐโฆ ๋๋ค๋ฅธ ๋ฌธ์ ๋ฐ์
์ฒ์์ ํด๊ฒฐํ ์ค ์์๋ค. ํโฆ ๊ทธ๋ฐ๋ฐ ๋ฌธ์ ๋ ์ดํ๋ฆฌ์ผ์ด์
๊ฐ์ฅ ์์์ ThemeProvider
๋ฅผ ๊ฐ์ธ๋์๊ธฐ ๋๋ฌธ์, ๊ทธ ํ์ ๋ชจ๋ ์ปดํฌ๋ํธ๊ฐ dynamic
์ผ๋ก ์ธํ lazy loading
์ฒ๋ฆฌ๊ฐ ๋์ด๋ฒ๋ฆฐ๋ค๋ ๊ฒ์ด๋ค. ์ฆ, ์น ํ์ด์ง ์ฒ์ ์ ์ ์ ๋คํธ์ํฌ ํญ์์ ์ฒซ๋ฒ์งธ html์ Preview
๋ก ๋ณด์๋ ๊ทธ๋ฅ ๋น ํ๋ฉด๋ง ๋ณด์ธ๋ค. ์ด๋ฌ๋ฉด Next์์์ SSR(ํน์ SSG)์ ์๋ฏธ๊ฐ ์ฌ๋ผ์ ธ๋ฒ๋ฆฐ๋คโฆใ
ํโฆ useEffect๋ฅผ ์ฌ์ฉํด๋ดค์ง๋ง, ๊ทธ๋ฌ๋ฉด ์ฒ์์ ๋ฐ๋ก ๋ผ์ดํธ ๋ชจ๋๋ก ๋ ๋๋ง๋์๋ค๊ฐ ๊ทธ ์ดํ์ ๋คํฌ ๋ชจ๋๋ก ๋ณ๊ฒฝ๋๋ค. ์ผ๋จ์ initialTheme์ light
๋ก ๊ณ ์ ํด๋๊ณ , ๋์ค์ ๋ค์ ๊ณ ๋ฏผํด๋ด์ผ๊ฒ ๋ค.(์ ์ด์ ์๋ฒ ๋ ๋๋ง์์ ์ ์ ์ ์ค์ ์ ์๊ณ ๋ ๋๋งํ๋ ๋ฐฉ๋ฒ์ด ๋ง์ด ๋๋ ์ถ๊ธฐ๋ ํ๋ค.)
react icon with tailwind
์ ๋ง ๋ณ ๊ฑฐ ์๋์ง๋ง, react icon์ className์ tailwindcss๊ฐ ์ ์ฉ๋๋ค๋ ์ฌ์คโฆ!!!!!
์ฌ์ง์ด text-
prefix๋ฅผ ๋ถ์ด๋ฉด icon์ content์ ์์์ด ๋ณ๊ฒฝ๋๊ณ bg-
prefix๋ฅผ ๋ถ์ด๋ฉด icon์ ๋ฐฐ๊ฒฝ์์ด ๋ณ๊ฒฝ๋๋ค. ์ฌ์ค ์์ด์ฝ๋ค ํ๋ํ๋ ์ฐพ์๊ฐ๋ฉด์ ์ฐ๋๊ฒ ๋๋ฌด ๋ถํธํ๋ค๊ณ ํฌ๋๊ฑฐ๋ ธ๋๋ฐ ์ด๊ฑด ์ซ ์ธ์
๐ ํ๊ณ
์๊ฐ๋ณด๋ค ๋น ๋ฅด์ง ์์ง๋ง ์๊ฐ๋ณด๋ค ์ฌ๋ฏธ์๋น