React 18

React 18

React 19 betaκ°€ 24λ…„ 04월에 μΆœμ‹œλ˜μ–΄ 볡슡 ν• κ²Έ 18에 λŒ€ν•΄ 글을 μž‘μ„±ν•©λ‹ˆλ‹€.

1. μžλ™ 배치 (Automatic Batching)

React 18μ—μ„œ κ°€μž₯ 큰 λ³€ν™” 쀑 ν•˜λ‚˜λŠ” μžλ™ λ°°μΉ˜μž…λ‹ˆλ‹€. μžλ™ λ°°μΉ˜λŠ” μ—¬λŸ¬ μƒνƒœ μ—…λ°μ΄νŠΈλ₯Ό ν•˜λ‚˜μ˜ λ Œλ”λ§μœΌλ‘œ λ³‘ν•©ν•˜μ—¬ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ˜ μ„±λŠ₯을 ν–₯μƒμ‹œν‚€λŠ” κΈ°λŠ₯μž…λ‹ˆλ‹€. 이전 λ²„μ „μ—μ„œλŠ” 이벀트 ν•Έλ“€λŸ¬ λ‚΄μ—μ„œλ§Œ λ°°μΉ˜κ°€ μΌμ–΄λ‚¬μ§€λ§Œ, React 18μ—μ„œλŠ” 비동기 μ½”λ“œ λ‚΄μ—μ„œλ„ μžλ™μœΌλ‘œ λ°°μΉ˜κ°€ μ΄λ£¨μ–΄μ§‘λ‹ˆλ‹€.

import { useState } from 'react';

function MyComponent() {
  const [count, setCount] = useState(0);
  const [text, setText] = useState('');

  const handleClick = async () => {
    await fetch('/api/data');
    setCount(c => c + 1);
    setText('Updated!');
  };

  return (
    <div>
      <button onClick={handleClick}>Click me</button>
      <p>{count}</p>
      <p>{text}</p>
    </div>
  );
}

μœ„ μ½”λ“œμ—μ„œ handleClick ν•¨μˆ˜λŠ” 비동기 ν•¨μˆ˜μ΄μ§€λ§Œ, μƒνƒœ μ—…λ°μ΄νŠΈλŠ” μžλ™μœΌλ‘œ λ°°μΉ˜λ˜μ–΄ ν•˜λ‚˜μ˜ λ Œλ”λ§μœΌλ‘œ μ²˜λ¦¬λ©λ‹ˆλ‹€. ν•΄λ‹Ή κΈ°λŠ₯으둜 ν”„λ‘œκ·Έλž¨ μ„±λŠ₯ μ΅œμ ν™”μ— 큰 도움이 λ©λ‹ˆλ‹€.


2. startTransition API

React 18은 μ‚¬μš©μž μΈν„°νŽ˜μ΄μŠ€κ°€ 보닀 λΆ€λ“œλŸ½κ³  λ°˜μ‘μ„± 있게 λ™μž‘ν•˜λ„λ‘ 돕기 μœ„ν•΄ μƒˆλ‘œμš΄ startTransition APIλ₯Ό λ„μž…ν–ˆμŠ΅λ‹ˆλ‹€. 이 APIλŠ” μƒνƒœ μ—…λ°μ΄νŠΈλ₯Ό β€˜μ „ν™˜β€™μœΌλ‘œ ν‘œμ‹œν•˜μ—¬, Reactκ°€ μ€‘μš”ν•œ μ—…λ°μ΄νŠΈλ₯Ό μš°μ„  μ²˜λ¦¬ν•˜κ³  덜 μ€‘μš”ν•œ μ—…λ°μ΄νŠΈλ₯Ό λ‚˜μ€‘μ— μ²˜λ¦¬ν•  수 있게 ν•©λ‹ˆλ‹€.

import { useState, startTransition } from 'react';

function MyComponent() {
  const [isPending, setIsPending] = useState(false);
  const [list, setList] = useState([]);

  const handleClick = () => {
    setIsPending(true);
    startTransition(() => {
      const newList = generateBigList(); // 큰 리슀트λ₯Ό μƒμ„±ν•˜λŠ” ν•¨μˆ˜
      setList(newList);
      setIsPending(false);
    });
  };

  return (
    <div>
      <button onClick={handleClick}>Generate List</button>
      {isPending ? <p>Loading...</p> : <List items={list} />}
    </div>
  );
}

μœ„ μ½”λ“œμ—μ„œ startTransition은 큰 리슀트λ₯Ό μƒμ„±ν•˜λŠ” μž‘μ—…μ„ μ „ν™˜μœΌλ‘œ μ²˜λ¦¬ν•˜μ—¬, μ‚¬μš©μžλŠ” λ²„νŠΌ 클릭 μ‹œ 지연 없이 즉각적인 ν”Όλ“œλ°±μ„ 받을 수 μžˆμŠ΅λ‹ˆλ‹€.


3. Concurrent Features (λ™μ‹œμ„± κΈ°λŠ₯)

React 18은 λ™μ‹œμ„± λͺ¨λ“œλ₯Ό 기본으둜 λ„μž…ν•˜μ—¬, 더 λ‚˜μ€ μ„±λŠ₯κ³Ό μ‚¬μš©μž κ²½ν—˜μ„ μ œκ³΅ν•©λ‹ˆλ‹€. λ™μ‹œμ„± λͺ¨λ“œλŠ” Reactκ°€ μ—¬λŸ¬ μƒνƒœ μ—…λ°μ΄νŠΈλ₯Ό 효율적으둜 μ²˜λ¦¬ν•  수 있게 ν•˜λ©°, μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ΄ 보닀 λΆ€λ“œλŸ½κ²Œ μž‘λ™ν•˜λ„λ‘ λ•μŠ΅λ‹ˆλ‹€. λ™μ‹œμ„± λͺ¨λ“œλ₯Ό μ‚¬μš©ν•˜λ €λ©΄, createRootλ₯Ό μ‚¬μš©ν•˜μ—¬ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ„ μ΄ˆκΈ°ν™”ν•΄μ•Ό ν•©λ‹ˆλ‹€.

import { createRoot } from 'react-dom/client';
import App from './App';

const container = document.getElementById('root');
const root = createRoot(container);
root.render(<App />);

λ™μ‹œμ„± λͺ¨λ“œμ˜ μž‘λ™ 방식 λ™μ‹œμ„± λͺ¨λ“œλŠ” μ΄λŸ¬ν•œ 문제λ₯Ό ν•΄κ²°ν•˜κΈ° μœ„ν•΄ μ—¬λŸ¬ μƒνƒœ μ—…λ°μ΄νŠΈλ₯Ό 효율적으둜 κ΄€λ¦¬ν•©λ‹ˆλ‹€. μ£Όμš” κ°œλ…μ€ λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€:

μž‘μ—… λΆ„ν• : κΈ΄ μž‘μ—…μ„ μ—¬λŸ¬ μž‘μ€ μž‘μ—…μœΌλ‘œ λΆ„ν• ν•˜μ—¬, Reactκ°€ μ€‘μš”ν•œ μž‘μ—…μ„ μš°μ„ μ μœΌλ‘œ μ²˜λ¦¬ν•  수 있게 ν•©λ‹ˆλ‹€. μž‘μ—… 쀑단 및 재개: ReactλŠ” μž‘μ—…μ„ μ€‘λ‹¨ν•˜κ³  μ€‘μš”ν•œ μž‘μ—…μ„ λ¨Όμ € μ²˜λ¦¬ν•œ ν›„, λ‹€μ‹œ μ€‘λ‹¨λœ μž‘μ—…μ„ μ΄μ–΄μ„œ ν•  수 μžˆμŠ΅λ‹ˆλ‹€. μ „ν™˜ 처리: ReactλŠ” μƒνƒœ μ—…λ°μ΄νŠΈλ₯Ό μ „ν™˜μœΌλ‘œ μ²˜λ¦¬ν•˜μ—¬, μ€‘μš”ν•œ μ—…λ°μ΄νŠΈμ™€ 덜 μ€‘μš”ν•œ μ—…λ°μ΄νŠΈλ₯Ό ꡬ뢄할 수 μžˆμŠ΅λ‹ˆλ‹€.

이 μ½”λ“œλ₯Ό 톡해 λ™μ‹œμ„± λͺ¨λ“œλ₯Ό ν™œμ„±ν™”ν•˜λ©΄, ReactλŠ” 더 λ‚˜μ€ λ Œλ”λ§ μ„±λŠ₯을 μ œκ³΅ν•˜κ³ , μ‚¬μš©μž μΈν„°νŽ˜μ΄μŠ€μ˜ 응닡성을 ν–₯μƒμ‹œν‚¬ 수 μžˆμŠ΅λ‹ˆλ‹€.


4. μ„œλ²„ μ»΄ν¬λ„ŒνŠΈ (Server Components)

React 18μ—μ„œλŠ” μ„œλ²„ μ»΄ν¬λ„ŒνŠΈλ₯Ό λ„μž…ν•˜μ—¬, μ„œλ²„μ—μ„œ 직접 λ Œλ”λ§ν•  수 μžˆλŠ” μ»΄ν¬λ„ŒνŠΈλ₯Ό λ§Œλ“€ 수 μžˆμŠ΅λ‹ˆλ‹€. μ΄λŠ” 초기 λ‘œλ”© μ‹œκ°„μ„ λ‹¨μΆ•ν•˜κ³ , ν΄λΌμ΄μ–ΈνŠΈ μΈ‘μ—μ„œ λΆˆν•„μš”ν•œ JavaScript λ‘œλ“œλ₯Ό μ€„μ΄λŠ” 데 도움이 λ©λ‹ˆλ‹€. μ„œλ²„ μ»΄ν¬λ„ŒνŠΈλŠ” 아직 μ‹€ν—˜ 단계에 μžˆμ§€λ§Œ, μ•žμœΌλ‘œ React의 μ€‘μš”ν•œ κΈ°λŠ₯으둜 자리 μž‘μ„ κ²ƒμœΌλ‘œ κΈ°λŒ€λ©λ‹ˆλ‹€.

// MyServerComponent.server.js
import React from 'react';

export default function MyServerComponent() {
  const data = fetchDataFromServer(); // μ„œλ²„μ—μ„œ 데이터λ₯Ό κ°€μ Έμ˜€λŠ” ν•¨μˆ˜
  return <div>{data}</div>;
}

μ„œλ²„ μ»΄ν¬λ„ŒνŠΈλŠ” μ„œλ²„μ—μ„œ λ Œλ”λ§λ˜κΈ° λ•Œλ¬Έμ— 초기 λ‘œλ”© μ‹œκ°„μ„ 크게 단좕할 수 μžˆμŠ΅λ‹ˆλ‹€. ν΄λΌμ΄μ–ΈνŠΈ μΈ‘μ—μ„œ ν•„μš”ν•œ JavaScript 양을 쀄이고, λΈŒλΌμš°μ €κ°€ 초기 λ‘œλ“œ μ‹œ 더 적은 μ–‘μ˜ 데이터λ₯Ό λ‹€μš΄λ‘œλ“œν•˜μ—¬ λΉ λ₯΄κ²Œ νŽ˜μ΄μ§€λ₯Ό λ Œλ”λ§ν•  수 μžˆμŠ΅λ‹ˆλ‹€.


5. μ„œμŠ€νŽœμŠ€ (Suspense)

React 18은 μ„œμŠ€νŽœμŠ€λ₯Ό 톡해 데이터 λ‘œλ”© μ‹œ 보닀 효율적인 처리λ₯Ό κ°€λŠ₯ν•˜κ²Œ ν•©λ‹ˆλ‹€. μ„œμŠ€νŽœμŠ€λŠ” μ»΄ν¬λ„ŒνŠΈκ°€ 비동기 μž‘μ—…μ„ μ™„λ£Œν•  λ•ŒκΉŒμ§€ λ‘œλ”© μƒνƒœλ₯Ό ν‘œμ‹œν•  수 μžˆλ„λ‘ λ„μ™€μ€λ‹ˆλ‹€. 이λ₯Ό 톡해 μ‚¬μš©μž κ²½ν—˜μ„ ν–₯μƒμ‹œν‚€κ³ , 비동기 μž‘μ—… μ™„λ£Œ ν›„ μ»΄ν¬λ„ŒνŠΈλ₯Ό λ Œλ”λ§ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

import React, { Suspense } from 'react';

const MyComponent = React.lazy(() => import('./MyComponent'));

function App() {
  return (
    <div>
      <Suspense fallback={<div>Loading...</div>}>
        <MyComponent />
      </Suspense>
    </div>
  );
}

μœ„ μ½”λ“œμ—μ„œ React.lazy와 Suspenseλ₯Ό μ‚¬μš©ν•˜μ—¬, MyComponentκ°€ λ‘œλ“œλ  λ•ŒκΉŒμ§€ λ‘œλ”© λ©”μ‹œμ§€λ₯Ό ν‘œμ‹œν•©λ‹ˆλ‹€. μ΄λŠ” μ‚¬μš©μžμ—κ²Œ 비동기 데이터 λ‘œλ”© μ€‘μž„μ„ λͺ…ν™•νžˆ μ•Œλ €μ€„ 수 μžˆμ–΄, 더 λ‚˜μ€ μ‚¬μš©μž κ²½ν—˜μ„ μ œκ³΅ν•©λ‹ˆλ‹€.


κ²°λ‘ 

React 18은 κ°œλ°œμžλ“€μ΄ 보닀 μ„±λŠ₯ 쒋은 μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ„ λ§Œλ“€ 수 μžˆλ„λ‘ λ•λŠ” λ‹€μ–‘ν•œ μƒˆλ‘œμš΄ κΈ°λŠ₯듀을 λ„μž…ν–ˆμŠ΅λ‹ˆλ‹€. μžλ™ 배치, startTransition API, λ™μ‹œμ„± κΈ°λŠ₯, μ„œλ²„ μ»΄ν¬λ„ŒνŠΈ, 그리고 μ„œμŠ€νŽœμŠ€λŠ” λͺ¨λ‘ 개발자 κ²½ν—˜μ„ ν–₯μƒμ‹œν‚€κ³ , μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ˜ μ„±λŠ₯을 κ·ΉλŒ€ν™”ν•˜λŠ” 데 큰 도움이 λ©λ‹ˆλ‹€.