๐Ÿ“– TIL - React์˜ ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ ์‰ฝ๊ฒŒ ์ดํ•ดํ•˜๊ธฐ

์Š˜ยท2025๋…„ 2์›” 22์ผ

๐Ÿ“– TIL

๋ชฉ๋ก ๋ณด๊ธฐ
63/90

React 18์—์„œ ๋„์ž…๋œ Concurrent Features(๋™์‹œ์„ฑ)์˜ ํ•ต์‹ฌ ๊ฐœ๋…๋“ค๊ณผ ์ด๊ฒƒ์ด ํ•ด๊ฒฐํ•˜๊ณ ์ž ํ•˜๋Š” ๋ฌธ์ œ๋“ค์„ ์ž์„ธํžˆ ์‚ดํŽด๋ณด์•˜์Šต๋‹ˆ๋‹ค.

ํ•ต์‹ฌ ์šฉ์–ด

Concurrent Features (๋™์‹œ์„ฑ)
Tearing (ํ‹ฐ์–ด๋ง)
State as a Snapshot (์Šค๋ƒ…์ƒท์œผ๋กœ์„œ์˜ ์ƒํƒœ)
Blocking vs Non-blocking Rendering

๐Ÿค” ๋ฌธ์ œ ์ ‘๊ทผ

1. ๊ธฐ์กด React์˜ ๋ Œ๋”๋ง ๋ฐฉ์‹

๋™๊ธฐ์‹(Synchronous) ๋ Œ๋”๋ง

  • ํ•œ ๋ฒˆ ์‹œ์ž‘๋œ ๋ Œ๋”๋ง์€ ์ค‘๋‹จ ๋ถˆ๊ฐ€
  • ํฐ ์ž‘์—…์ด ์žˆ์œผ๋ฉด UI๊ฐ€ ์™„์ „ํžˆ ๋ฉˆ์ถค
  • ์‚ฌ์šฉ์ž ์ž…๋ ฅ์ด ์ง€์—ฐ๋˜๋Š” ๋ฌธ์ œ

2. ํ•ด๊ฒฐํ•˜๋ ค๋˜ ์„ธ ๊ฐ€์ง€ ํฐ ๋ฌธ์ œ

๋ธ”๋กœํ‚น ๋ Œ๋”๋ง์˜ ํ•œ๊ณ„

  • ๊ธด ๋ Œ๋”๋ง ์ž‘์—… ๋™์•ˆ ๋ธŒ๋ผ์šฐ์ € ๋ฉˆ์ถค
  • ์‚ฌ์šฉ์ž ์ž…๋ ฅ ๋ฌด์‹œ๋˜๋Š” ํ˜„์ƒ

UI ์ผ๊ด€์„ฑ ๋ฌธ์ œ (Tearing)

  • ํ™”๋ฉด์ด ์ผ์‹œ์ ์œผ๋กœ ๋ถˆ์ผ์น˜ํ•˜๋Š” ํ˜„์ƒ
  • ํŠนํžˆ ์™ธ๋ถ€ ์ƒํƒœ ๊ด€๋ฆฌ์‹œ ์ž์ฃผ ๋ฐœ์ƒ(ex. redux)

์ƒํƒœ ์—…๋ฐ์ดํŠธ์˜ ์˜ˆ์ธก ๊ฐ€๋Šฅ์„ฑ

์—ฐ์†๋œ ์ƒํƒœ ์—…๋ฐ์ดํŠธ์˜ ์ฒ˜๋ฆฌ
๋ฐฐ์น˜ ์—…๋ฐ์ดํŠธ์˜ ํ•œ๊ณ„

๐Ÿ“Œ ์™œ ์ด๋Ÿฐ ๊ธฐ๋Šฅ์ด ํ•„์š”ํ–ˆ์„๊นŒ์š”?

๊ธฐ์กด์˜ ๋ฌธ์ œ์ 

์นดํŽ˜์—์„œ ์ฃผ๋ฌธ์„ ๋ฐ›๋Š” ์ƒํ™ฉ์œผ๋กœ ๋น„์œ ํ•ด๋ณผ๊ฒŒ์š”!

React 18 ์ด์ „: ํ•œ ๋ช…์˜ ์ง์›์ด ์ฃผ๋ฌธ์„ ๋ฐ›๊ณ  ์Œ๋ฃŒ๋ฅผ ๋งŒ๋“œ๋Š” ์ƒํ™ฉ

  • ๊ธด ์ฃผ๋ฌธ์ด ๋“ค์–ด์˜ค๋ฉด ๋‹ค๋ฅธ ์†๋‹˜๋“ค์€ ๊ณ„์† ๊ธฐ๋‹ค๋ ค์•ผ ํ•จ
  • ์ค‘๊ฐ„์— ๊ธ‰ํ•œ ์ฃผ๋ฌธ์ด ๋“ค์–ด์™€๋„ ์ˆœ์„œ๋ฅผ ๋ฐ”๊ฟ€ ์ˆ˜ ์—†์Œ
  • ์†๋‹˜๋“ค์ด ์˜ค๋ž˜ ๊ธฐ๋‹ค๋ฆฌ๊ฒŒ ๋˜๋ฉด์„œ ๋ถˆ๋งŒ์ด ์ƒ๊น€

์ด๋Ÿฐ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด React 18์—์„œ๋Š” ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ๋„์ž…ํ–ˆ์–ด์š”!

๐Ÿค” ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ๋“ค์€ ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋‚˜์š”?

1. ๋™์‹œ์„ฑ(Concurrent Features)

๋ณต์žกํ•œ ์‡ผํ•‘๋ชฐ ํŽ˜์ด์ง€๋ฅผ ์˜ˆ๋กœ ๋“ค์–ด๋ณผ๊นŒ์š”?

์ด์ „ ๋ฐฉ์‹:

  • ์ƒํ’ˆ ๋ชฉ๋ก ๋กœ๋”ฉ ์ค‘์—๋Š” ๊ฒ€์ƒ‰์ฐฝ๋„ ๋ฉˆ์ถค
  • ํ•„ํ„ฐ ์„ ํƒ๋„ ๋ฒ„๋ฒ…์ž„
  • ์‚ฌ์šฉ์ž๊ฐ€ ๋‹ต๋‹ตํ•จ์„ ๋А๋‚Œ
// ๊ธฐ์กด React (๋™๊ธฐ์  ๋ Œ๋”๋ง)
function ProductList() {
  const [products, setProducts] = useState([]);
  
  useEffect(() => {
    // ๋ฌด๊ฑฐ์šด API ํ˜ธ์ถœ
    fetchProducts().then(data => setProducts(data));
  }, []);

  // ๋ฌธ์ œ: API ์‘๋‹ต์„ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๋™์•ˆ ์ „์ฒด UI๊ฐ€ ๋ธ”๋ก๋จ
  return <div>{/* ์ œํ’ˆ ๋ชฉ๋ก ๋ Œ๋”๋ง */}</div>;
}

์ƒˆ๋กœ์šด ๋ฐฉ์‹:

function ProductList() {
  const [isPending, startTransition] = useTransition();
  const [products, setProducts] = useState([]);

  const loadProducts = () => {
    // ๋‚ฎ์€ ์šฐ์„ ์ˆœ์œ„๋กœ ํ‘œ์‹œ
    startTransition(() => {
      fetchProducts().then(data => setProducts(data));
    });
  };

  return (
    <div>
      {isPending ? (
        // ์Šค์ผˆ๋ ˆํ†ค UI๋‚˜ ๋กœ๋”ฉ ํ‘œ์‹œ
        <SkeletonLoader />
      ) : (
        // ์‹ค์ œ ์ œํ’ˆ ๋ชฉ๋ก
        <ProductGrid products={products} />
      )}
      
      {/* ์ด ๋ถ€๋ถ„์€ ๊ณ„์† ๋ฐ˜์‘ ๊ฐ€๋Šฅ! */}
      <SearchBar />
      <FilterOptions />
    </div>
  );
}

2. ํ‹ฐ์–ด๋ง(Tearing) ํ˜„์ƒ

์‹ค์‹œ๊ฐ„ ์ฃผ์‹ ๊ฐ€๊ฒฉ ํ‘œ์‹œ ์•ฑ์„ ์˜ˆ๋กœ ๋“ค์–ด๋ณผ๊ฒŒ์š”:

๋ฌธ์ œ ์ƒํ™ฉ:

// ์ „์—ญ ์ฃผ์‹ ๊ฐ€๊ฒฉ
let stockPrice = 1000;

function StockWidget() {
  // ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ์—์„œ ๊ฐ™์€ ๊ฐ€๊ฒฉ์„ ํ‘œ์‹œํ•˜๋Š”๋ฐ...
  const [price, setPrice] = useState(stockPrice);
  
  // ๊ฐ€๊ฒฉ์ด ๋ฐ”๋€Œ๋ฉด ์—…๋ฐ์ดํŠธ
  useEffect(() => {
    const handler = () => setPrice(stockPrice);
    subscribe(handler);
    return () => unsubscribe(handler);
  }, []);

  return <div>ํ˜„์žฌ ๊ฐ€๊ฒฉ: {price}์›</div>;
}

๋ฌธ์ œ์ :

  • StockWidget1: "ํ˜„์žฌ ๊ฐ€๊ฒฉ: 1000์›"
  • StockWidget2: "ํ˜„์žฌ ๊ฐ€๊ฒฉ: 1100์›"
  • ๊ฐ™์€ ๋ฐ์ดํ„ฐ์ธ๋ฐ ๋‹ค๋ฅด๊ฒŒ ๋ณด์ž„!

ํ•ด๊ฒฐ๋ฐฉ๋ฒ•:

function StockWidget() {
  // useSyncExternalStore๋กœ ํ•ด๊ฒฐ
  const price = useSyncExternalStore(
    subscribe,
    () => stockPrice
  );

  return <div>ํ˜„์žฌ ๊ฐ€๊ฒฉ: {price}์›</div>;
}

3. ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€ ํ‹ฐ์–ด๋ง

  • Zustand: ์ž์ฒด์ ์œผ๋กœ ํ‹ฐ์–ด๋ง ๋ฐฉ์ง€ ๊ตฌํ˜„
  • Redux: ๋ช…์‹œ์ ์œผ๋กœ useSyncExternalStore ์‚ฌ์šฉ ํ•„์š”
  • ๊ฑฑ์ •ํ•˜์ง€ ์•Š์•„๋„ ๋˜๋Š” ์ด์œ : ๋Œ€๋ถ€๋ถ„์˜ ์ตœ์‹  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์ด ์ด๋ฏธ ์ฒ˜๋ฆฌํ•˜๊ณ  ์žˆ์Œ

โœจ ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์˜ ์žฅ์ 

  1. ๋” ๋ถ€๋“œ๋Ÿฌ์šด ์‚ฌ์šฉ์ž ๊ฒฝํ—˜

    • ๋ฌด๊ฑฐ์šด ์ž‘์—… ์ค‘์—๋„ UI ๋ฐ˜์‘์„ฑ ์œ ์ง€
    • ๋กœ๋”ฉ ์ค‘์— ์Šค์ผˆ๋ ˆํ†ค UI ํ‘œ์‹œ ๊ฐ€๋Šฅ
    • ์ค‘์š”ํ•œ ์—…๋ฐ์ดํŠธ ์šฐ์„  ์ฒ˜๋ฆฌ
  2. ์•ˆ์ •์ ์ธ ๋ฐ์ดํ„ฐ ํ‘œ์‹œ

    • ํ‹ฐ์–ด๋ง ์—†๋Š” ์ผ๊ด€๋œ UI
    • ์‚ฌ์šฉ์ž ํ˜ผ๋ž€ ๋ฐฉ์ง€
  3. ๊ฐœ๋ฐœ์ž ๊ฒฝํ—˜ ๊ฐœ์„ 

    • ์„ฑ๋Šฅ ๊ฑฑ์ • ์—†์ด ๊ธฐ๋Šฅ ๊ฐœ๋ฐœ ๊ฐ€๋Šฅ
    • ์ž๋™์œผ๋กœ ์ตœ์ ํ™” ์ฒ˜๋ฆฌ

โญ๏ธ ์ •๋ฆฌํ•˜๋ฉด

  • React 18์˜ ๋™์‹œ์„ฑ: ๊ธด ์ž‘์—…์ด ๋‹ค๋ฅธ ์ž‘์—…์„ ๋ฐฉํ•ดํ•˜์ง€ ์•Š๋„๋ก
  • ํ‹ฐ์–ด๋ง ๋ฐฉ์ง€: ํ™”๋ฉด์— ํ‘œ์‹œ๋˜๋Š” ๋ฐ์ดํ„ฐ์˜ ์ผ๊ด€์„ฑ ๋ณด์žฅ
  • ์ตœ์‹  ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค: ์ด๋ฏธ ์ด๋Ÿฐ ๋ฌธ์ œ๋“ค์„ ๊ณ ๋ คํ•˜์—ฌ ์„ค๊ณ„๋จ

์‹ค์ œ ์ ์šฉ ์‹œ์—๋Š”:
1. ๋ฌด๊ฑฐ์šด ์ž‘์—…์€ startTransition์œผ๋กœ ๊ฐ์‹ธ๊ธฐ
2. ์™ธ๋ถ€ ์ƒํƒœ ์‚ฌ์šฉ ์‹œ ์ ์ ˆํ•œ ๋„๊ตฌ ์„ ํƒํ•˜๊ธฐ (Zustand ๋“ฑ)
3. ๋กœ๋”ฉ ์ƒํƒœ์— ๋Œ€ํ•œ UI ์ค€๋น„ํ•˜๊ธฐ (์Šค์ผˆ๋ ˆํ†ค ๋“ฑ)

profile
์ฃผ๋‹ˆ์–ด ํ”„๋ก ํŠธ์—”๋“œ ์„ฑ์žฅ๊ธฐ ๊ธฐ๋ก๊ธฐ๋ก

0๊ฐœ์˜ ๋Œ“๊ธ€