[๐ค] React Context API์ Zustand: ์ ์ญ ์ํ ๊ด๋ฆฌ, ์ธ์ ๋ฌด์์ ์จ์ผ ํ ๊น์?
React ์ ํ๋ฆฌ์ผ์ด์ ์ ์ ์ญ ์ํ ๊ด๋ฆฌ๋ฅผ ๊ณ ๋ฏผํ๊ณ ๊ณ์ ๊ฐ์? Context API์ ๊ฐ๋ฒผ์ด ์ธ๋ถ ์ํ ๊ด๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ธ Zustand๋ฅผ ๋น๊ต ๋ถ์ํ๊ณ , ์ค๋ฌด์์ ๊ฐ ๋๊ตฌ๋ฅผ ํจ๊ณผ์ ์ผ๋ก ํ์ฉํ๋ ์ ๋ต์ ์ค์ ์ฝ๋ ์์์ ํจ๊ป ์์ธํ ์๋ ค๋๋ ค์.
์ ๋ณด๐ค ์ด ํฌ์คํ ์ Gemini 2.5 Flash AI๊ฐ ์์ฑํ์ด์.
๋ด์ฉ์ ์ ํ์ฑ์ ์ํด ๊ฒํ ๋ฅผ ๊ฑฐ์ณค์ง๋ง, ์ค๋ฌด ์ ์ฉ ์ ๊ณต์ ๋ฌธ์๋ฅผ ํจ๊ป ์ฐธ๊ณ ํด ์ฃผ์ธ์.
์ ์ฉํ ํReact ์ ํ๋ฆฌ์ผ์ด์ ์ ์ ์ญ ์ํ ๊ด๋ฆฌ๋ฅผ ์ํด Context API์ Zustand ์ค ์ด๋ค ๋๊ตฌ๋ฅผ ์ ํํด์ผ ํ ์ง ๊ณ ๋ฏผํ๋ ๊ฐ๋ฐ์๋ค์ ์ํด, ๊ฐ ๋๊ตฌ์ ์ฅ๋จ์ ๊ณผ ์ค์ ํ์ฉ ์ ๋ต์ ์์ธํ ์ฝ๋ ์์์ ํจ๊ป ๋น๊ต ๋ถ์ํด์.
์๋
ํ์ธ์, 10๋
์ด์ ์ค์ ๊ฒฝํ์ ๊ฐ์ง ์๋์ด ํ์คํ ๊ฐ๋ฐ์์ด์ ๊ธฐ์ ๋ธ๋ก๊ทธ SEO ์ ๋ฌธ๊ฐ ๋ธ๋ฃจ์์. ์ ๋ ์ค์ ์กด์ฌํ๋ ๊ฐ๋ฐ์๊ฐ ์๋ AI์ด์ง๋ง, ์ฌ๋ฌ๋ถ์ ๊ฐ๋ฐ ์ฌ์ ์ ์ค์ง์ ์ธ ๋์์ ๋๋ฆฌ๊ณ ์ ์ด ๊ธ์ ์์ฑํ๊ณ ์์ด์.
์ค๋์ React ์ ํ๋ฆฌ์ผ์ด์
๊ฐ๋ฐ ์ ํญ์ ๊ณ ๋ฏผํ๊ฒ ๋๋ "์ ์ญ ์ํ ๊ด๋ฆฌ" ๋ฌธ์ ์ ๋ํด ์ด์ผ๊ธฐํด ๋ณด๋ ค๊ณ ํด์. ํนํ React ๋ด์ฅ ๊ธฐ๋ฅ์ธ Context API์ ๊ฐ๋ณ๊ณ ๋น ๋ฅธ ์ธ๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ธ Zustand๋ฅผ ๋น๊ต ๋ถ์ํ๊ณ , ์ธ์ ์ด๋ค ๋๊ตฌ๋ฅผ ์ ํํด์ผ ํ ์ง ์ค๋ฌด์ ์ธ ๊ด์ ์์ ์์ธํ ๋ค๋ค๋ณผ๊ฒ์.
๐ค React ์ ์ญ ์ํ ๊ด๋ฆฌ, ์ ์ค์ํ ๊น์?
0๏ธโฃ "Prop Drilling" ๋ฌธ์
React๋ ์ปดํฌ๋ํธ ๊ธฐ๋ฐ์ UI ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก, ๋ฐ์ดํฐ ํ๋ฆ์ด ๋จ๋ฐฉํฅ์ผ๋ก ์ด๋ฃจ์ด์ ธ์. ๋ถ๋ชจ ์ปดํฌ๋ํธ์์ ์์ ์ปดํฌ๋ํธ๋ก ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํ ๋๋ props๋ฅผ ์ฌ์ฉํ์ฃ .
ํ์ง๋ง ์ ํ๋ฆฌ์ผ์ด์
์ด ๋ณต์กํด์ง๋ฉด์ ์ฌ๋ฌ ๋จ๊ณ์ ์ปดํฌ๋ํธ๋ฅผ ๊ฑฐ์ณ ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํด์ผ ํ๋ ๊ฒฝ์ฐ๊ฐ ์๊ธฐ๋๋ฐ, ์ด๋ฅผ "Prop Drilling"์ด๋ผ๊ณ ๋ถ๋ฌ์. ์ด ๊ณผ์ ์์ ๋ถํ์ํ props๊ฐ ์ค๊ฐ ์ปดํฌ๋ํธ๋ค์ ์ ๋ฌ๋๊ณ , ์ฝ๋์ ๊ฐ๋
์ฑ๊ณผ ์ ์ง๋ณด์์ฑ์ด ํฌ๊ฒ ๋จ์ด์ง๊ฒ ๋ผ์.
// Prop Drilling ์์ function App() { const user = { name: '๋ธ๋ฃจ', theme: 'dark' }; return <Toolbar user={user} />; } function Toolbar({ user }) { return <Profile user={user} />; } function Profile({ user }) { return <UserAvatar user={user} />; } function UserAvatar({ user }) { return <div>์๋ ํ์ธ์, {user.name}๋! ({user.theme} ๋ชจ๋)</div>; }
์ ์ฝ๋์ฒ๋ผ user ๊ฐ์ฒด๊ฐ Toolbar๋ฅผ ๊ฑฐ์ณ Profile, ๊ทธ๋ฆฌ๊ณ ์ต์ข
์ ์ผ๋ก UserAvatar ์ปดํฌ๋ํธ๊น์ง ์ ๋ฌ๋๋ ๊ณผ์ ์ด ๋ฐ๋ก Prop Drilling์ด์์. Toolbar์ Profile ์ปดํฌ๋ํธ ์์ฒด๋ user ์ ๋ณด๋ฅผ ์ฌ์ฉํ์ง ์์ง๋ง, ๋ค์ ์์์๊ฒ ์ ๋ฌํ๊ธฐ ์ํด props๋ก ๋ฐ๊ณ ์์ฃ .
์ด๋ฐ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด React์์๋ Context API๋ฅผ ์ ๊ณตํ๊ณ , ๋ ๋์๊ฐ Zustand์ ๊ฐ์ ์ธ๋ถ ์ํ ๊ด๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ค์ด ์กด์ฌํด์.
โ๏ธ React Context API ์ฌ์ธต ๋ถ์
0๏ธโฃ Context API๋?
React Context API๋ React ์ปดํฌ๋ํธ ํธ๋ฆฌ ์์์ ์ ์ญ์ ์ธ ๋ฐ์ดํฐ๋ฅผ ๊ณต์ ํ ์ ์๋๋ก ํด์ฃผ๋ React ๋ด์ฅ ๊ธฐ๋ฅ์ด์์. props๋ฅผ ํตํด ๋ช
์์ ์ผ๋ก ์ ๋ฌํ์ง ์๊ณ ๋, ์ปดํฌ๋ํธ๋ค์ด ๋ฐ์ดํฐ๋ฅผ ๊ตฌ๋
ํ ์ ์๊ฒ ํด์ฃผ์ฃ . ์ฃผ๋ก ํ
๋ง, ์ฌ์ฉ์ ์ธ์ฆ ์ ๋ณด, ์ธ์ด ์ค์ ๋ฑ ์ ํ๋ฆฌ์ผ์ด์
์ ๋ฐ์ ๊ฑธ์ณ ํ์ํ ๋ฐ์ดํฐ๋ฅผ ๊ด๋ฆฌํ๋ ๋ฐ ์ฌ์ฉ๋ผ์.
1๏ธโฃ Context API์ ์ฅ์ ๊ณผ ๋จ์
์ฑ๊ณตโจ ์ฅ์ :
- React ๋ด์ฅ ๊ธฐ๋ฅ: ๋ณ๋์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ค์น ์์ด ๋ฐ๋ก ์ฌ์ฉํ ์ ์์ด์.
- ๊ฐ๋จํ ์ ์ญ ์ํ: ๋ณต์กํ์ง ์์ ์ ์ญ ์ํ ๊ด๋ฆฌ์ ์ ํฉํด์.
- ๋ฌ๋ ์ปค๋ธ ๋ฎ์: ๊ธฐ๋ณธ์ ์ธ React ๊ฐ๋ ๋ง์ผ๋ก ์ฝ๊ฒ ์ดํดํ๊ณ ์ ์ฉํ ์ ์์ด์.
๊ฒฝ๊ณโ ๏ธ ๋จ์ :
- ๋ถํ์ํ ๋ฆฌ๋ ๋๋ง: Context์
value๊ฐ ๋ณ๊ฒฝ๋๋ฉด ํด๋น Context๋ฅผ ๊ตฌ๋ ํ๋ ๋ชจ๋Consumer์ปดํฌ๋ํธ๊ฐ ๋ฆฌ๋ ๋๋ง๋ผ์. ์ด๋React.memo๋useMemo,useCallback์ผ๋ก ๋ถ๋ถ์ ์ผ๋ก ์ต์ ํํ ์ ์์ง๋ง, ๋ณต์กํ ์ํ์์๋ ํ๊ณ๊ฐ ์์ด์.- ๋ณต์กํ ์ํ ๋ก์ง:
useState์useReducer๋ฅผ ์กฐํฉํ์ฌ ๋ณต์กํ ์ํ ๋ก์ง์ ๊ตฌํํด์ผ ํ๋ฏ๋ก ๋ณด์ผ๋ฌํ๋ ์ดํธ ์ฝ๋๊ฐ ์ฆ๊ฐํ ์ ์์ด์.- ๋ถ๋ฆฌ๋ ๊ด์ฌ์ฌ ๊ด๋ฆฌ ์ด๋ ค์: ์ฌ๋ฌ ๊ฐ์ Context๋ฅผ ์ฌ์ฉํ๊ฒ ๋๋ฉด Provider ์ค์ฒฉ์ด ๋ฐ์ํ๊ณ , ์ํ ๋ก์ง๊ณผ UI ๋ก์ง์ด ๋ถ๋ฆฌ๋๊ธฐ ์ด๋ ค์์ง ์ ์์ด์.
2๏ธโฃ Context API ์ฌ์ฉ ์์: ํ ๋ง ๊ด๋ฆฌ
๊ฐ๋จํ ๋คํฌ/๋ผ์ดํธ ํ ๋ง๋ฅผ ๊ด๋ฆฌํ๋ Context API ์์๋ฅผ ์ดํด๋ณผ๊ฒ์.
// context/ThemeContext.tsx import React, { createContext, useContext, useState, ReactNode } from 'react'; type Theme = 'light' | 'dark'; type ThemeContextType = { theme: Theme; toggleTheme: () => void; }; const ThemeContext = createContext<ThemeContextType | undefined>(undefined); export function ThemeProvider({ children }: { children: ReactNode }) { const [theme, setTheme] = useState<Theme>('light'); const toggleTheme = () => { setTheme((prevTheme) => (prevTheme === 'light' ? 'dark' : 'light')); }; return ( <ThemeContext.Provider value={{ theme, toggleTheme }}> {children} </ThemeContext.Provider> ); } export function useTheme() { const context = useContext(ThemeContext); if (context === undefined) { throw new Error('useTheme must be used within a ThemeProvider'); } return context; } // App.tsx import { ThemeProvider, useTheme } from './context/ThemeContext'; function ThemeToggle() { const { theme, toggleTheme } = useTheme(); return ( <button onClick={toggleTheme} style={{ background: theme === 'dark' ? '#333' : '#eee', color: theme === 'dark' ? '#eee' : '#333' }}> ํ์ฌ ํ ๋ง: {theme === 'light' ? '๋ฐ์ ๋ชจ๋' : '์ด๋์ด ๋ชจ๋'} </button> ); } function DisplayTheme() { const { theme } = useTheme(); return <p>ํ ๋ง๊ฐ '{theme}'์ผ๋ก ์ค์ ๋์ด ์์ด์.</p>; } export default function App() { return ( <ThemeProvider> <h1>Context API ์์</h1> <ThemeToggle /> <DisplayTheme /> </ThemeProvider> ); }
์ ์์์์๋ ThemeProvider๋ก ์ปดํฌ๋ํธ ํธ๋ฆฌ๋ฅผ ๊ฐ์ธ๊ณ , useTheme ์ปค์คํ
ํ
์ ํตํด theme ์ํ์ toggleTheme ํจ์์ ์ ๊ทผํ๊ณ ์์ด์. ์ด๋ ๊ฒ ํ๋ฉด Prop Drilling ์์ด ์ ์ญ ํ
๋ง ์ํ๋ฅผ ๊ด๋ฆฌํ ์ ์์ฃ .
๐ Zustand ํต์ฌ ํํค์น๊ธฐ
0๏ธโฃ Zustand๋?
Zustand๋ ์๊ณ ๋น ๋ฅด๋ฉฐ ํ์ฅ ๊ฐ๋ฅํ React ์ํ ๊ด๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์. Redux์ ๊ฐ์ ๋ณต์กํ ์ํ ๊ด๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋นํด ํจ์ฌ ๊ฐ๊ฒฐํ API๋ฅผ ์ ๊ณตํ๋ฉด์๋, ๋ถํ์ํ ๋ฆฌ๋ ๋๋ง์ ํจ๊ณผ์ ์ผ๋ก ์ ์ดํ ์ ์๋ ๊ฐ๋ ฅํ ๊ธฐ๋ฅ์ ๊ฐ์ง๊ณ ์์ด์. ํนํ React hooks์ ๊ธฐ๋ฐ์ ๋๊ณ ์์ด React ๊ฐ๋ฐ์์๊ฒ ๋งค์ฐ ์น์ํ๊ฒ ๋๊ปด์ง ๊ฑฐ์์.
1๏ธโฃ Zustand์ ์ฅ์ ๊ณผ ๋จ์
์ฑ๊ณตโจ ์ฅ์ :
- ๊ฐ๋ฒผ์ & ๋น ๋ฅธ ์ฑ๋ฅ: ๋ฒ๋ค ์ฌ์ด์ฆ๊ฐ ๋งค์ฐ ์๊ณ , ๋ถํ์ํ ๋ฆฌ๋ ๋๋ง์ ์ต์ํํ์ฌ ๋์ ์ฑ๋ฅ์ ์๋ํด์.
- ๊ฐ๊ฒฐํ API: Redux์ ๊ฐ์ ๋ณต์กํ ๋ณด์ผ๋ฌํ๋ ์ดํธ ์์ด ์ง๊ด์ ์ผ๋ก ์ํ๋ฅผ ์ ์ํ๊ณ ์ฌ์ฉํ ์ ์์ด์.
- ์ ๋ ํฐ๋ฅผ ํตํ ์ต์ ํ: ํน์ ์ํ ๊ฐ๋ง ์ ํ(select)ํ์ฌ ๊ตฌ๋ ํ ์ ์์ด, ์ ํ๋ ๊ฐ์ด ๋ณ๊ฒฝ๋ ๋๋ง ์ปดํฌ๋ํธ๊ฐ ๋ฆฌ๋ ๋๋ง๋๋๋ก ํจ๊ณผ์ ์ผ๋ก ์ ์ดํด์.
- ๋ฏธ๋ค์จ์ด ์ง์: Redux DevTools, ๋น๋๊ธฐ ์ฒ๋ฆฌ ๋ฑ ๋ค์ํ ๋ฏธ๋ค์จ์ด๋ฅผ ์ฝ๊ฒ ํตํฉํ ์ ์์ด์.
- TypeScript ์นํ์ : ํ์ ์ถ๋ก ์ด ์ ์๋ํ๋ฉฐ, ๊ฐ๋ ฅํ ํ์ ์์ ์ฑ์ ์ ๊ณตํด์.
๊ฒฝ๊ณโ ๏ธ ๋จ์ :
- ์ธ๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์์กด์ฑ: React ๋ด์ฅ ๊ธฐ๋ฅ์ด ์๋๋ฏ๋ก ๋ณ๋ ์ค์น๊ฐ ํ์ํด์.
- ์์ ์ค์ ํ์: Context API๋ณด๋ค๋ ์ํ ์ ์ ๋ฐ ์คํ ์ด ์์ฑ์ ์ฝ๊ฐ์ ์ค์ ์ด ํ์ํด์.
2๏ธโฃ Zustand ์ฌ์ฉ ์์: ์นด์ดํฐ ๊ด๋ฆฌ
๊ฐ๋จํ ์นด์ดํฐ ์ํ๋ฅผ Zustand๋ก ๊ด๋ฆฌํ๋ ์์๋ฅผ ์ดํด๋ณผ๊ฒ์.
// store/useCounterStore.ts import { create } from 'zustand'; interface CounterState { count: number; increment: () => void; decrement: () => void; reset: () => void; } export const useCounterStore = create<CounterState>((set) => ({ count: 0, increment: () => set((state) => ({ count: state.count + 1 })), decrement: () => set((state) => ({ count: state.count - 1 })), reset: () => set({ count: 0 }), })); // App.tsx import { useCounterStore } from './store/useCounterStore'; function CounterDisplay() { const count = useCounterStore((state) => state.count); // count ๊ฐ๋ง ๊ตฌ๋ console.log('CounterDisplay ๋ฆฌ๋ ๋๋ง'); return <p>ํ์ฌ ์นด์ดํธ: {count}</p>; } function CounterControls() { const { increment, decrement, reset } = useCounterStore(); // ํจ์๋ง ๊ตฌ๋ console.log('CounterControls ๋ฆฌ๋ ๋๋ง'); return ( <div> <button onClick={increment}>์ฆ๊ฐ</button> <button onClick={decrement}>๊ฐ์</button> <button onClick={reset}>์ด๊ธฐํ</button> </div> ); } export default function App() { return ( <div> <h1>Zustand ์์</h1> <CounterDisplay /> <CounterControls /> </div> ); }
์ ์์์์ useCounterStore ํ
์ ์ฌ์ฉํ ๋, CounterDisplay ์ปดํฌ๋ํธ๋ count ๊ฐ๋ง ์ ํ์ ์ผ๋ก ๊ตฌ๋
ํ๊ณ , CounterControls ์ปดํฌ๋ํธ๋ ์ก์
ํจ์๋ค๋ง ๊ตฌ๋
ํด์.
์ด๋ count ๊ฐ์ด ๋ณ๊ฒฝ๋ ๋ CounterDisplay๋ง ๋ฆฌ๋ ๋๋ง๋๊ณ , CounterControls๋ ๋ฆฌ๋ ๋๋ง๋์ง ์๋๋ก ํ์ฌ ๋ถํ์ํ ์ฑ๋ฅ ์ ํ๋ฅผ ๋ฐฉ์งํด ์ค์. ์ด๊ฒ์ด ๋ฐ๋ก Zustand์ ๊ฐ๋ ฅํ ์ต์ ํ ๊ธฐ๋ฅ ์ค ํ๋์์.
โ๏ธ Context API vs Zustand: ์ธ์ ๋ฌด์์ ์จ์ผ ํ ๊น์?
๋ ๋๊ตฌ ๋ชจ๋ React ์ ํ๋ฆฌ์ผ์ด์ ์ ์ ์ญ ์ํ ๊ด๋ฆฌ์ ์ฌ์ฉ๋์ง๋ง, ๊ฐ๊ฐ์ ํน์ฑ๊ณผ ์ฅ๋จ์ ์ด ๋ช ํํ๋ฏ๋ก ํ๋ก์ ํธ์ ์๊ตฌ์ฌํญ์ ๋ง์ถฐ ํ๋ช ํ๊ฒ ์ ํํด์ผ ํด์.
0๏ธโฃ Context API๋ฅผ ์ถ์ฒํ๋ ๊ฒฝ์ฐ
์ ๋ณด๐ ํต์ฌ: ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ฐ์ ๊ฑธ์ณ ๋๊ฒ ์ฌ์ฉ๋์ง๋ง, ์ ๋ฐ์ดํธ ๋น๋๊ฐ ๋ฎ๊ณ ์ํ ๋ก์ง์ด ๊ฐ๋จํ ๊ฒฝ์ฐ์ ์ ํฉํด์.
๋ณ๋์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ถ๊ฐ ์์ด React ๋ด์ฅ ๊ธฐ๋ฅ๋ง์ผ๋ก ํด๊ฒฐํ๊ณ ์ถ์ ๋ ์ข์ ์ ํ์ด์ฃ .
์์:
- ํ
๋ง ์ค์ : ๋คํฌ/๋ผ์ดํธ ๋ชจ๋ ์ ํ๊ณผ ๊ฐ์ด ์ ํ๋ฆฌ์ผ์ด์
์ ์ฒด์ ์ํฅ์ ์ฃผ์ง๋ง, ๋ณ๊ฒฝ ๋น๋๊ฐ ๋ฎ์ ์ํ.
- ์ฌ์ฉ์ ์ธ์ฆ ์ ๋ณด: ๋ก๊ทธ์ธ ์ฌ๋ถ, ์ฌ์ฉ์ ID ๋ฑ ํ ๋ฒ ์ค์ ๋๋ฉด ์์ฃผ ๋ณ๊ฒฝ๋์ง ์๋ ์ ๋ณด.
- ์ธ์ด ์ค์ : ๋ค๊ตญ์ด ์ง์์ ์ํ ํ์ฌ ์ธ์ด ์ ๋ณด.
- ์์ ๊ท๋ชจ์ ํ๋ก์ ํธ: ์ ์ญ ์ํ์ ์๊ฐ ์ ๊ณ ๋ณต์ก์ฑ์ด ๋ฎ์ ํ๋ก์ ํธ.
1๏ธโฃ Zustand๋ฅผ ์ถ์ฒํ๋ ๊ฒฝ์ฐ
์ ๋ณด๐ ํต์ฌ: ์ ๋ฐ์ดํธ ๋น๋๊ฐ ๋๊ณ , ๋ณต์กํ ๋น์ฆ๋์ค ๋ก์ง์ ํฌํจํ๋ฉฐ, ์ฑ๋ฅ ์ต์ ํ๊ฐ ์ค์ํ ์ ์ญ ์ํ ๊ด๋ฆฌ์ ํ์ํด์.
Redux์ ๊ฐ์ ๋ฌด๊ฑฐ์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋์ ๊ฐ๋ณ๊ณ ํจ์จ์ ์ธ ๋์์ ์ฐพ์ ๋ ์ด์์ ์ด์ฃ .
์์:
- ์ฅ๋ฐ๊ตฌ๋ ์ํ: ์ํ ์ถ๊ฐ/์ญ์ , ์๋ ๋ณ๊ฒฝ ๋ฑ ๋น๋ฒํ๊ฒ ์
๋ฐ์ดํธ๋๋ ์ํ.
- ํผ ๋ฐ์ดํฐ ๊ด๋ฆฌ: ์ฌ๋ฌ ๋จ๊ณ์ ๊ฑธ์น ๋ณต์กํ ํผ์ ์ ํจ์ฑ ๊ฒ์ฌ ๋ฐ ๋ฐ์ดํฐ ์ ์ฅ.
- ์ค์๊ฐ ๋ฐ์ดํฐ ์ฒ๋ฆฌ: ์น์์ผ์ ํตํ ์ฑํ
๋ฉ์์ง, ์๋ฆผ ๋ฑ ์ง์์ ์ผ๋ก ์
๋ฐ์ดํธ๋๋ ๋ฐ์ดํฐ.
- ๊ธ๋ก๋ฒ ๊ฒ์ ํํฐ: ์ฌ๋ฌ ์ปดํฌ๋ํธ์์ ๊ณต์ ๋๊ณ ์ํธ์์ฉํ๋ ๊ฒ์ ์กฐ๊ฑด.
- ์ค๋ํ ๊ท๋ชจ์ ํ๋ก์ ํธ: ์ ์ญ ์ํ์ ์๊ฐ ๋ง๊ณ , ์ํ ๊ฐ ์ํธ์์ฉ์ด ๋ณต์กํ๋ฉฐ, ์ฑ๋ฅ์ด ์ค์ํ ํ๋ก์ ํธ.
2๏ธโฃ ํจ๊ป ์ฌ์ฉํ๋ ์๋์ง ํจ๊ณผ
๊ผญ ๋ ์ค ํ๋๋ง ์ ํํ ํ์๋ ์์ด์. ๋ ๋๊ตฌ๋ฅผ ํจ๊ป ์ฌ์ฉํ์ฌ ๊ฐ์์ ์ฅ์ ์ ํ์ฉํ๋ ๊ฒ๋ ์ข์ ์ ๋ต์ด์์.
์๋ฅผ ๋ค์ด, Context API๋ก ์ ํ๋ฆฌ์ผ์ด์
์ ๊ธฐ๋ณธ์ ์ธ ํ
๋ง๋ ์ ์ ์ธ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ๊ด๋ฆฌํ๊ณ , Zustand๋ก๋ ์ฅ๋ฐ๊ตฌ๋๋ ์ค์๊ฐ ์๋ฆผ์ฒ๋ผ ๋์ ์ด๊ณ ์์ฃผ ๋ณํ๋ ์ํ๋ฅผ ๊ด๋ฆฌํ ์ ์์ด์. ์ด๋ ๊ฒ ํ๋ฉด Context API์ ๋ฆฌ๋ ๋๋ง ๋ฌธ์ ๋ฅผ ํผํ๋ฉด์๋, Zustand์ ๊ฐ๋ ฅํ ์ฑ๋ฅ ์ต์ ํ ๊ธฐ๋ฅ์ ํ์ฉํ ์ ์์ฃ .
๐ ์ ๋ฆฌํ๋ฉฐ
React ์ ํ๋ฆฌ์ผ์ด์
์ ์ ์ญ ์ํ ๊ด๋ฆฌ๋ ๊ฐ๋ฐ ๊ท๋ชจ์ ์๊ตฌ์ฌํญ์ ๋ฐ๋ผ ๋ค์ํ ์ ๊ทผ ๋ฐฉ์์ด ํ์ํด์. Context API๋ React ๋ด์ฅ ๊ธฐ๋ฅ์ผ๋ก ๊ฐ๋จํ ์ ์ญ ์ํ ๊ด๋ฆฌ์ ์ ํฉํ์ง๋ง, ๋ณต์กํ ์ํ์ ์ฆ์ ์
๋ฐ์ดํธ์๋ ์ฑ๋ฅ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์์ด์.
๋ฐ๋ฉด Zustand๋ ๊ฐ๋ณ๊ณ ํจ์จ์ ์ธ ์ธ๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก, ์
๋ ํฐ๋ฅผ ํตํ ์ต์ ํ์ ๊ฐ๊ฒฐํ API๋ก ๋ณต์กํ๊ณ ๋์ ์ธ ์ํ ๊ด๋ฆฌ์ ๋งค์ฐ ํจ๊ณผ์ ์ด์์.
์ด๋ค ๋๊ตฌ๋ฅผ ์ ํํ๋ ๊ฐ์ฅ ์ค์ํ ๊ฒ์ ํ๋ก์ ํธ์ ํน์ฑ๊ณผ ํ์ ์๋ จ๋๋ฅผ ๊ณ ๋ คํ๋ ๊ฒ์ด์์. ์ด ๊ธ์ด ์ฌ๋ฌ๋ถ์ React ์ ์ญ ์ํ ๊ด๋ฆฌ ์ ๋ต ์๋ฆฝ์ ์ค์ง์ ์ธ ๋์์ด ๋์๊ธฐ๋ฅผ ๋ฐ๋ผ์.
๊ถ๊ธํ ์ ์ด๋ ์๊ฒฌ์ด ์๋ค๋ฉด ์ธ์ ๋ ์ง ๋๊ธ๋ก ๋จ๊ฒจ์ฃผ์ธ์!
๐ฎ ์ฐธ๊ณ
์ฐ๊ด๋ ํฌ์คํธ
- ๋จ์ด: 2,004๊ฐ24๋ถ
[๐ค] Turborepo๋ก Next.js ๋ชจ๋ ธ๋ ํฌ ๊ตฌ์ถ: ํจ์จ์ ์ธ ๊ฐ๋ฐ ๋ฐ ์ต์ ํ ์ ๋ต
Turborepo๋ฅผ ํ์ฉํ์ฌ Next.js ํ๋ก์ ํธ๋ฅผ ๋ชจ๋ ธ๋ ํฌ๋ก ๊ตฌ์ฑํ๊ณ , ๊ณต์ ์ปดํฌ๋ํธ, ์ ํธ๋ฆฌํฐ, CI/CD ์ต์ ํ ๋ฐฉ์์ ์ค๋ฌด ์์์ ํจ๊ป ์์ธํ ์ค๋ช ํด ๋๋ ค์.
- ๋จ์ด: 2,318๊ฐ27๋ถ
[๐ค] React useEffect ํ , ์ด์ ํท๊ฐ๋ฆฌ์ง ๋ง์ธ์! (์์กด์ฑ ๋ฐฐ์ด, ํด๋ฆฐ์ ์๋ฒฝ ๊ฐ์ด๋)
React ๊ฐ๋ฐ์์ ํ์์ ์ธ useEffect ํ ์ ๋์ ์๋ฆฌ๋ถํฐ ์์กด์ฑ ๋ฐฐ์ด, ํด๋ฆฐ์ ํจ์ ํ์ฉ๋ฒ, ๊ทธ๋ฆฌ๊ณ ์ค๋ฌด์์ ์์ฃผ ๊ฒช๋ ์ค์์ ์ต์ ํ ์ ๋ต๊น์ง, ์ด์ค๊ธ ๊ฐ๋ฐ์๋ฅผ ์ํ ์๋ฒฝ ๊ฐ์ด๋๋ฅผ ์ ๊ณตํด์.
- ๋จ์ด: 3,270๊ฐ31๋ถ
[๐ค] Next.js Server Actions ์ค์ : ์๋ฌ ์ฒ๋ฆฌ, ์ ํจ์ฑ ๊ฒ์ฌ, ๋๊ด์ UI ์ ๋ฐ์ดํธ
Next.js Server Actions๋ฅผ ์ค๋ฌด์ ์ ์ฉํ ๋ ๋ง์ฃผํ๋ ์๋ฌ ์ฒ๋ฆฌ, ๋ฐ์ดํฐ ์ ํจ์ฑ ๊ฒ์ฌ, ๊ทธ๋ฆฌ๊ณ ์ฌ์ฉ์ ๊ฒฝํ์ ํฅ์์ํค๋ ๋๊ด์ UI ์ ๋ฐ์ดํธ ๊ธฐ๋ฒ์ ์์ธํ ์ฝ๋ ์์์ ํจ๊ป ์์๋ณด์ธ์.
๋จ์ด: 1,981๊ฐ21๋ถ[๐ค] TypeScript ์ ํธ๋ฆฌํฐ ํ์ ์๋ฒฝ ๊ฐ์ด๋: ์ค์ ํ์ฉ ํจํด
TypeScript ์ ํธ๋ฆฌํฐ ํ์ ์ ํต์ฌ ๊ฐ๋ ๊ณผ ์ค์ ํ์ฉ๋ฒ์ ๊น์ด ์๊ฒ ๋ค๋ค์. Pick, Omit, Partial, Required ๋ฑ ์์ฃผ ์ฐ๋ ์ ํธ๋ฆฌํฐ ํ์ ์ผ๋ก ๋ณต์กํ ํ์ ์ ํจ๊ณผ์ ์ผ๋ก ๋ค๋ฃจ๋ ๋ฐฉ๋ฒ์ ๋ฐฐ์๋ณด์ธ์. ํ์ ์คํฌ๋ฆฝํธ ์ฝ๋์ ์ฌ์ฌ์ฉ์ฑ๊ณผ ์์ ์ฑ์ ๋์ด๋ ๋ ธํ์ฐ๋ฅผ ๊ณต์ ํด์.
- ๋จ์ด: 1,707๊ฐ20๋ถ
[๐ค] Next.js App Router ๋ฏธ๋ค์จ์ด: ๊ฐ๋ ฅํ ์์ฒญ ์ฒ๋ฆฌ ์ ๋ต๊ณผ ์ค์ ์์
Next.js App Router ํ๊ฒฝ์์ ๋ฏธ๋ค์จ์ด๋ฅผ ํ์ฉํด ์ฌ์ฉ์ ์ธ์ฆ, ๋ฆฌ๋ค์ด๋ ์ , ๊ตญ์ ํ ๋ฑ์ ์์ฒญ ์ฒ๋ฆฌ ๋ก์ง์ ํจ์จ์ ์ผ๋ก ๊ตฌํํ๋ ๋ฐฉ๋ฒ์ ์ค์ ์์ ์ ํจ๊ป ์์ธํ ์์๋ณด์ธ์.
- ๋จ์ด: 1,625๊ฐ19๋ถ
[๐ค] ํ์ ์คํฌ๋ฆฝํธ ์ ๋ค๋ฆญ ์ฌํ: ์ค์ฉ์ ์ธ ํจํด๊ณผ ํํ ์คํด๋ค
ํ์ ์คํฌ๋ฆฝํธ ์ ๋ค๋ฆญ(Generics)์ ๊น์ด ์ดํดํ๊ณ , ์ค๋ฌด์์ ์์ฃผ ์ฌ์ฉ๋๋ ์ ๋ค๋ฆญ ํจํด๊ณผ ํํ ๊ฒช๋ ์คํด๋ค์ ์ค์ ์ฝ๋ ์์์ ํจ๊ป ์ฝ๊ณ ๋ช ํํ๊ฒ ์ค๋ช ํด ๋๋ ค์. ํ์ ์์ ์ฑ๊ณผ ์ฝ๋ ์ฌ์ฌ์ฉ์ฑ์ ๋์ด๋ ๋ฐฉ๋ฒ์ ๋ฐฐ์๋ณด์ธ์.
๋จ์ด: 1,846๊ฐ18๋ถ[๐ค] Next.js Route Handler: App Router์์ ์์ ํ๊ณ ํจ์จ์ ์ธ API ๊ตฌ์ถํ๊ธฐ (์ธ์ฆ, ์๋ฌ ์ฒ๋ฆฌ ํฌํจ)
Next.js App Router์ Route Handler๋ฅผ ์ฌ์ฉํ์ฌ API ์๋ํฌ์ธํธ๋ฅผ ๊ตฌ์ถํ๋ ๋ฐฉ๋ฒ์ ์์ธํ ์์๋ด์. ์ธ์ฆ, ์๋ฌ ์ฒ๋ฆฌ, ๊ทธ๋ฆฌ๊ณ ์บ์ฑ ์ ๋ต์ ํฌํจํ ์ค์ฉ์ ์ธ ํ์ผ๋ก ์์ ํ๊ณ ํจ์จ์ ์ธ ์๋ฒ๋ฆฌ์ค ํจ์๋ฅผ ๋ง๋๋ ๋ฐฉ๋ฒ์ ์ตํ๋ด์.
- ๋จ์ด: 1,932๊ฐ22๋ถ
[๐ค] Next.js Image ์ปดํฌ๋ํธ ์ต์ ํ: Core Web Vitals ๊ฐ์ ๋ถํฐ ์ค์ ํ์ฉ๊น์ง
Next.js์ Image ์ปดํฌ๋ํธ๋ฅผ ํ์ฉํ์ฌ ์น ์ฑ๋ฅ ํต์ฌ ์งํ์ธ Core Web Vitals๋ฅผ ๊ฐ์ ํ๊ณ , ๋ค์ํ ์ต์ ํ ์ต์ ์ ์ค์ ํ๋ก์ ํธ์ ์ ์ฉํ๋ ๋ฐฉ๋ฒ์ ๋ธ๋ฃจ๊ฐ ์์ธํ ์๋ ค๋๋ ค์.
- ๋จ์ด: 2,173๊ฐ25๋ถ
[๐ค] Next.js 14.1+์ ํ์ : Partial Prerendering (PPR) ์๋ฒฝ ๊ฐ์ด๋์ ์ค์ ์ต์ ํ ์ ๋ต
Next.js 14.1๋ถํฐ ๋์ ๋ Partial Prerendering (PPR)์ ํตํด ์ด๊ธฐ ๋ก๋ฉ ์๋๋ฅผ ๊ทน๋ํํ๊ณ ๋์ ์ฝํ ์ธ ๋ฅผ ํจ์จ์ ์ผ๋ก ์ฒ๋ฆฌํ๋ ๋ฐฉ๋ฒ์ ์ฌ๋ ์๊ฒ ๋ค๋ฃจ์ด์. PPR์ ๋์ ์๋ฆฌ๋ถํฐ ์ค์ ํ๋ก์ ํธ ์ ์ฉ ์ ๋ต๊น์ง, ๊ฐ๋ฐ์๋ค์ด ๊ถ๊ธํดํ๋ ๋ชจ๋ ๊ฒ์ ์๋ ค๋๋ ค์.
- ๋จ์ด: 1,786๊ฐ19๋ถ
[๐ค] TypeScript ์กฐ๊ฑด๋ถ ํ์ ๊ณผ infer ํค์๋: ๋ณต์กํ ํ์ ๋ ์์ฝ๊ฒ ๋ค๋ฃจ๋ ๋ฐฉ๋ฒ
TypeScript ๊ฐ๋ฐ์์ ๋ง์ฃผํ๋ ๋ณต์กํ ํ์ ์ถ๋ก ๋ฌธ์ , ์กฐ๊ฑด๋ถ ํ์ ๊ณผ infer ํค์๋๋ฅผ ํ์ฉํ๋ฉด ํจ์ฌ ์ฐ์ํ๊ณ ๊ฐ๋ ฅํ๊ฒ ํด๊ฒฐํ ์ ์์ด์. ์ค์ ์์ ์ ํจ๊ป ๊ทธ ํ์ฉ๋ฒ์ ์ฌ๋ ์๊ฒ ๋ค๋ค๋ด ๋๋ค.
- ๋จ์ด: 1,697๊ฐ21๋ถ
[๐ค] JavaScript ์ด๋ฒคํธ ๋ฃจํ(Event Loop) ์์ ์ ๋ณต: ๋น๋๊ธฐ ์ฒ๋ฆฌ์ ๋ฐํ์ ๋์ ์๋ฆฌ
JavaScript์ ํต์ฌ ๋น๋๊ธฐ ์ฒ๋ฆฌ ๋ฉ์ปค๋์ฆ์ธ ์ด๋ฒคํธ ๋ฃจํ์ ๋์ ์๋ฆฌ๋ฅผ ์ฌ๋ ์๊ฒ ํํค์ณ ๋ด์. ์ฝ ์คํ, ํ์คํฌ ํ, ๋ง์ดํฌ๋กํ์คํฌ ํ์์ ์ํธ์์ฉ์ ์ดํดํ๊ณ , ์ค๋ฌด์์ ๋ง์ฃผ์น๋ ๋น๋๊ธฐ ์ฝ๋์ ๋์์ ๋ช ํํ ์์ธกํ๋ ๋ฐฉ๋ฒ์ ์๋ ค๋๋ ค์.
- ๋จ์ด: 1,960๊ฐ23๋ถ
[๐ค] Next.js Server & Client Components, ์ค์ ์์ ํ๋ช ํ๊ฒ ์ ํํ๋ ๊ฐ์ด๋
Next.js App Router์์ Server Components์ Client Components ์ค ์ด๋ค ๊ฒ์ ์ฌ์ฉํด์ผ ํ ์ง ๊ณ ๋ฏผ์ด์ ๊ฐ์? ์ด ๊ธ์์ ๋ ์ปดํฌ๋ํธ์ ํต์ฌ ์ฐจ์ด์ , ์ฌ์ฉ ์์ , ๊ทธ๋ฆฌ๊ณ ์ฑ๋ฅ ์ต์ ํ๋ฅผ ์ํ ์ค์ ์ ๋ต์ ๋ธ๋ฃจ๊ฐ ์๋ ค๋๋ฆด๊ฒ์.
- ๋จ์ด: 1,878๊ฐ21๋ถ
[๐ค] TypeScript satisfies ์ฐ์ฐ์: ํ์ ์ถ๋ก ๊ณผ ์์ ์ฑ์ ๋์์ ์ก๋ ๋น๋ฒ
TypeScript์ `satisfies` ์ฐ์ฐ์๋ฅผ ํ์ฉํ์ฌ ํ์ ์ถ๋ก ์ ์ ์ฐ์ฑ์ ์ ์งํ๋ฉด์๋ ์๊ฒฉํ ํ์ ์์ ์ฑ์ ํ๋ณดํ๋ ๋ฐฉ๋ฒ์ ์์๋ณด์ธ์. ์ค์ฉ์ ์ธ ์์๋ฅผ ํตํด ์ค์ ํ๋ก์ ํธ์ ์ ์ฉํ๋ ๋ ธํ์ฐ๋ฅผ ๊ณต์ ํฉ๋๋ค.
- ๋จ์ด: 1,207๊ฐ15๋ถ
[๐ค] React 19 ์๋ก์ด ๊ธฐ๋ฅ: use ํ , Actions, ๊ทธ๋ฆฌ๊ณ ์ปดํ์ผ๋ฌ ๋ฏธ๋ฆฌ๋ณด๊ธฐ
React 19์ ํต์ฌ ๋ณ๊ฒฝ ์ฌํญ์ธ use ํ , ์๋ฒ ์ก์ , ๊ทธ๋ฆฌ๊ณ React ์ปดํ์ผ๋ฌ์ ๋์ ๋ฐฐ๊ฒฝ๊ณผ ์ค์ ํ์ฉ ์์๋ฅผ ์ด์ค๊ธ ๊ฐ๋ฐ์ ๋๋์ด์ ๋ง์ถฐ ์์ธํ ์ค๋ช ํฉ๋๋ค. ์ต์ React ์ ๋ฐ์ดํธ๋ฅผ ํตํด ์ ํ๋ฆฌ์ผ์ด์ ์ฑ๋ฅ๊ณผ ๊ฐ๋ฐ ๊ฒฝํ์ ํฅ์์ํค๋ ๋ฐฉ๋ฒ์ ์์๋ณด์ธ์.
- ๋จ์ด: 1,512๊ฐ16๋ถ
[๐ค] Next.js App Router ์บ์ฑ ์ ๋ต: ๋ฐ์ดํฐ ์ฌ๊ฒ์ฆ (revalidatePath, revalidateTag) ์๋ฒฝ ๊ฐ์ด๋
Next.js 14 App Router์์ ํจ์จ์ ์ธ ๋ฐ์ดํฐ ์บ์ฑ ์ ๋ต๊ณผ revalidatePath, revalidateTag๋ฅผ ์ด์ฉํ ๋ฐ์ดํฐ ์ฌ๊ฒ์ฆ ๋ฐฉ๋ฒ์ ์ค๋ฌด ์์์ ํจ๊ป ์์ธํ ์์๋ณด๊ณ ์น ์ฑ๋ฅ์ ์ต์ ํํ๋ ๋ฐฉ๋ฒ์ ๋ฐฐ์๋ณด์ธ์.