August 4, 2025

๐Ÿ”„ ๋ฌด๋ถ„๋ณ„ํ•œ ์ „์—ญ ์ƒํƒœ(Global State) ์‚ฌ์šฉ: ์˜ˆ์ธก ๋ถˆ๊ฐ€๋Šฅํ•œ ์ƒํƒœ ๋ณ€ํ™”์™€ ์„ฑ๋Šฅ ๋ณ‘๋ชฉ, ๐Ÿชข ๋ณต์žกํ•œ ์˜์กด์„ฑ

React
JavaScript
์ƒํƒœ๊ด€๋ฆฌ
์„ฑ๋Šฅ
์•„ํ‚คํ…์ฒ˜
์ปดํฌ๋„ŒํŠธ
UX

Summary

๋ฌด๋ถ„๋ณ„ํ•œ ์ „์—ญ ์ƒํƒœ ์‚ฌ์šฉ์€ ์˜ˆ์ธก ๋ถˆ๊ฐ€๋Šฅํ•œ ์ƒํƒœ ๋ณ€ํ™”, ์„ฑ๋Šฅ ์ €ํ•˜, ์œ ์ง€๋ณด์ˆ˜ ์–ด๋ ค์›€, ๋””๋ฒ„๊น… ๋ณต์žก์„ฑ ์ฆ๊ฐ€๋ฅผ ์ดˆ๋ž˜ํ•ฉ๋‹ˆ๋‹ค. ์ ์ ˆํ•œ ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ, Context API, ์ตœ์ ํ™” ๊ธฐ๋ฒ•, ๋””๋ฒ„๊น… ๋„๊ตฌ๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์ „์—ญ ์ƒํƒœ๋ฅผ ํšจ์œจ์ ์ด๊ณ  ํˆฌ๋ช…ํ•˜๊ฒŒ ๊ด€๋ฆฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

Why Wrong?

์ „์—ญ ์ƒํƒœ๋ฅผ ๊ณผ๋„ํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๋ฉด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ „์ฒด์— ๊ฑธ์ณ ์ƒํƒœ ๋ณ€ํ™”๊ฐ€ ์˜ˆ์ธก ๋ถˆ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋ฐœ์ƒํ•˜๊ณ , ํŠน์ • ์ปดํฌ๋„ŒํŠธ์—์„œ ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ ๋ถˆํ•„์š”ํ•˜๊ฒŒ ๋งŽ์€ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฆฌ๋ Œ๋”๋ง๋˜์–ด ์„ฑ๋Šฅ ์ €ํ•˜๋ฅผ ์ดˆ๋ž˜ํ•ฉ๋‹ˆ๋‹ค. ์ปดํฌ๋„ŒํŠธ ๊ฐ„์˜ ์˜์กด์„ฑ์ด ๋†’์•„์ ธ ์ฝ”๋“œ ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ์–ด๋ ค์›Œ์ง€๊ณ , ์ƒํƒœ ๋ณ€ํ™” ์ถ”์ ์ด ํž˜๋“ค์–ด ๋””๋ฒ„๊น…์ด ๋ณต์žกํ•ด์ง‘๋‹ˆ๋‹ค.

How to Fix?

  1. ๋ช…ํ™•ํ•œ ์ƒํƒœ ๊ด€๋ฆฌ ๋ชฉํ‘œ ์„ค์ •: ์–ด๋–ค ์ƒํƒœ๊ฐ€ ์ „์—ญ์ ์œผ๋กœ ๊ด€๋ฆฌ๋˜์–ด์•ผ ํ•˜๋Š”์ง€ ๋ช…ํ™•ํžˆ ์ •์˜ํ•˜๊ณ , ๋กœ์ปฌ ์ƒํƒœ๋กœ ๊ด€๋ฆฌ ๊ฐ€๋Šฅํ•œ ๋ถ€๋ถ„์€ ๋ถ„๋ฆฌํ•ฉ๋‹ˆ๋‹ค. 2. ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์„ ํƒ: Redux, Zustand, Recoil ๋“ฑ ์ ์ ˆํ•œ ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ ํƒํ•˜์—ฌ ์ƒํƒœ ๊ด€๋ฆฌ๋ฅผ ์ฒด๊ณ„ํ™”ํ•ฉ๋‹ˆ๋‹ค. 3. Context API ํ™œ์šฉ: ๊ฐ„๋‹จํ•œ ์ „์—ญ ์ƒํƒœ๋Š” React Context API๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๊ด€๋ฆฌํ•˜๊ณ , ๋ณต์žกํ•œ ์ƒํƒœ ๊ด€๋ฆฌ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. 4. ์ƒํƒœ ์—…๋ฐ์ดํŠธ ์ตœ์ ํ™”: ์ƒํƒœ ์—…๋ฐ์ดํŠธ ์‹œ ๋ถˆํ•„์š”ํ•œ ๋ฆฌ๋ Œ๋”๋ง์„ ์ตœ์†Œํ™”ํ•˜๊ธฐ ์œ„ํ•ด useMemo, useCallback ํ›…์„ ํ™œ์šฉํ•˜๊ณ , Immer ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ถˆ๋ณ€์„ฑ์„ ์œ ์ง€ํ•˜๋ฉด์„œ ํšจ์œจ์ ์ธ ์ƒํƒœ ์—…๋ฐ์ดํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. 5. ์ƒํƒœ ๋ณ€ํ™” ๋กœ๊น… ๋ฐ ๋””๋ฒ„๊น… ๋„๊ตฌ ํ™œ์šฉ: ์ƒํƒœ ๋ณ€ํ™”๋ฅผ ์ถ”์ ํ•˜๊ณ  ๋””๋ฒ„๊น…ํ•˜๊ธฐ ์œ„ํ•ด Redux DevTools์™€ ๊ฐ™์€ ๋„๊ตฌ๋ฅผ ํ™œ์šฉํ•ฉ๋‹ˆ๋‹ค. 6. ๊ด€์‹ฌ์‚ฌ ๋ถ„๋ฆฌ: ์ „์—ญ ์ƒํƒœ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ์™€ ๊ทธ๋ ‡์ง€ ์•Š์€ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ช…ํ™•ํžˆ ๋ถ„๋ฆฌํ•˜์—ฌ ์˜์กด์„ฑ์„ ๋‚ฎ์ถฅ๋‹ˆ๋‹ค.

์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋‚˜ Context API๋ฅผ ์‚ฌ์šฉํ•ด ์ „์—ญ ์ƒํƒœ๋กœ ๊ด€๋ฆฌํ•˜๋˜, ์ƒํƒœ ์—…๋ฐ์ดํŠธ ๋ฒ”์œ„๋ฅผ ์ขํžˆ๊ณ , ๋ถˆํ•„์š”ํ•œ ๋ฆฌ๋ Œ๋”๋ง์„ ๋ฐฉ์ง€ํ•˜๋Š” ์ตœ์ ํ™” ๊ธฐ๋ฒ•์„ ์ ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ, ์ƒํƒœ ๋ณ€ํ™” ์ถ”์  ๋ฐ ๋””๋ฒ„๊น… ๋„๊ตฌ๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ƒํƒœ๋ฅผ ํˆฌ๋ช…ํ•˜๊ฒŒ ๊ด€๋ฆฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

Before Code (Bad)

// ์ „์—ญ ๋ณ€์ˆ˜๋ฅผ ์ด์šฉํ•œ ์ƒํƒœ ๊ด€๋ฆฌ (์˜ˆ์‹œ, ์‹ค์ œ๋กœ๋Š” ๋” ๋ณต์žกํ•œ ๋กœ์ง์ด ์žˆ์„ ์ˆ˜ ์žˆ์Œ)
let theme = 'light';

function toggleTheme() {
  theme = theme === 'light' ? 'dark' : 'light';
  // ๊ฐ•์ œ๋กœ ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ ๋ฆฌ๋ Œ๋”๋ง (๋งค์šฐ ๋น„ํšจ์œจ์ )
  forceUpdateAllComponents(); 
}

function MyComponent() {
  return (
    <div>
      Current theme: {theme}
      <button onClick={toggleTheme}>Toggle Theme</button>
    </div>
  );
}

After Code (Good)

// React Context๋ฅผ ์ด์šฉํ•œ ์ƒํƒœ ๊ด€๋ฆฌ
import React, { createContext, useState, useContext } from 'react';

const ThemeContext = createContext();

function ThemeProvider({ children }) {
  const [theme, setTheme] = useState('light');

  const toggleTheme = () => {
    setTheme(prevTheme => (prevTheme === 'light' ? 'dark' : 'light'));
  };

  return (
    <ThemeContext.Provider value={{ theme, toggleTheme }}>
      {children}
    </ThemeContext.Provider>
  );
}

function useTheme() {
  return useContext(ThemeContext);
}

function MyComponent() {
  const { theme, toggleTheme } = useTheme();

  return (
    <div>
      Current theme: {theme}
      <button onClick={toggleTheme}>Toggle Theme</button>
    </div>
  );
}

// App.js
function App() {
  return (
    <ThemeProvider>
      <MyComponent />
    </ThemeProvider>
  );
}