HooneyLog

React 18의 주요 변경 사항

프로필 이미지

Seunghoon Shin

2024년 11월 24일 04:13

    올해 4월 기준으로 React 19 버전의 릴리스 후보가 공개 되었는데요.

    하지만 아직 정식 출시가 안되었으며 곧 출시가 되지 않을까 생각됩니다.

    그 전에 많은 변화가 있었던 리액트 18에서는 주로 어떤게 바뀌었는지 다시 한번 살펴보겠습니다.

    리액트 18의 주요 업데이트 사항 및 예시


    1. 동시성 렌더링 도입

    동시성 렌더링을 도입하여 사용자 인터페이스의 응답성을 향상시켰습니다. 이를 통해 긴급한 업데이트와 비긴급한 업데이트를 구분하여 처리할 수 있으며, 사용자 경험을 개선하는 데 기여합니다.

    예시:

    import { useState, useTransition } from 'react';
    
    function App() {
      const [isPending, startTransition] = useTransition();
      const [value, setValue] = useState('');
    
      const handleChange = (e) => {
        startTransition(() => {
          setValue(e.target.value);
        });
      };
    
      return (
        <div>
          <input type="text" onChange={handleChange} />
          {isPending ? '로딩 중...' : <ExpensiveComponent value={value} />}
        </div>
      );
    }
    
    

    위 예시에서 useTransition 훅을 사용하여 입력 변화에 따른 비긴급 업데이트를 처리하고 있습니다.


    2. 자동 배칭 도입

    여러 상태 업데이트를 자동으로 하나의 렌더링으로 묶어 처리합니다. 이를 통해 불필요한 렌더링을 줄이고 성능을 최적화할 수 있습니다.

    예시:

    import { useState } from 'react';
    
    function App() {
      const [count, setCount] = useState(0);
      const [flag, setFlag] = useState(false);
    
      const handleClick = () => {
        setCount((c) => c + 1);
        setFlag((f) => !f);
        // 리액트 19에서는 두 상태 업데이트가 자동으로 배칭되어 한 번의 렌더링만 발생합니다.
      };
    
      return <button onClick={handleClick}>클릭</button>;
    }
    
    

    이전 버전에서는 이벤트 핸들러 내부에서 발생하는 상태 업데이트만 배치 처리를 지원했지만, 리액트 19에서는 비동기 함수 내에서도 자동 배칭이 적용됩니다.


    3. useId 훅 도입

    서버 사이드 렌더링(SSR)과 클라이언트 사이드 렌더링 간의 ID 불일치 문제를 해결하기 위해 useId 훅이 도입되었습니다. 이를 통해 고유한 ID를 생성하여 접근성을 높이고, 컴포넌트 간의 일관성을 유지할 수 있습니다.

    예시:

    import { useId } from 'react';
    
    function App() {
      const id = useId();
    
      return (
        <div>
          <label htmlFor={id}>이름:</label>
          <input id={id} type="text" />
        </div>
      );
    }
    
    

    useId 훅을 사용하여 고유한 ID를 생성하고, 라벨과 입력 필드에 동일한 ID를 적용하여 접근성을 향상시킵니다.


    4. useTransition 훅 도입

    비긴급한 상태 업데이트를 처리할 수 있는 useTransition 훅이 추가되었습니다. 이를 통해 사용자 인터페이스의 응답성을 유지하면서도 복잡한 상태 변화를 관리할 수 있습니다.

    예시:

    import { useState, useTransition } from 'react';
    
    function App() {
      const [isPending, startTransition] = useTransition();
      const [list, setList] = useState([]);
    
      const handleClick = () => {
        startTransition(() => {
          const newList = generateBigList();
          setList(newList);
        });
      };
    
      return (
        <div>
          <button onClick={handleClick}>리스트 생성</button>
          {isPending ? '로딩 중...' : <ListComponent items={list} />}
        </div>
      );
    }
    
    

    useTransition 훅을 사용하여 대량의 리스트 생성을 비긴급 업데이트로 처리하고, 로딩 상태를 표시하여 사용자 경험을 개선합니다.


    5. 서버 사이드 렌더링 개선

    스트리밍과 동시성을 활용하여 서버 사이드 렌더링의 성능을 향상시켰습니다. 이를 통해 초기 로딩 시간을 단축하고, SEO 성능을 개선할 수 있습니다.

    예시:

    import { renderToPipeableStream } from 'react-dom/server';
    import App from './App';
    
    function handleRequest(req, res) {
      const { pipe } = renderToPipeableStream(<App />, {
        onShellReady() {
          res.statusCode = 200;
          res.setHeader('Content-type', 'text/html');
          pipe(res);
        },
        onError(err) {
          console.error(err);
          res.statusCode = 500;
          res.send('서버 에러');
        },
      });
    }
    
    

    renderToPipeableStream을 사용하여 스트리밍 방식으로 서버 사이드 렌더링을 수행하고, 초기 로딩 시간을 단축합니다.


    6. Suspense 기능 확장

    Suspense 컴포넌트의 기능이 확장되어 데이터 로딩 시 로딩 상태를 보다 효율적으로 관리할 수 있게 되었습니다. 이를 통해 사용자 경험을 향상시키고, 코드의 가독성을 높일 수 있습니다.

    예시:

    import { Suspense } from 'react';
    import DataComponent from './DataComponent';
    
    function App() {
      return (
        <Suspense fallback={<div>로딩 중...</div>}>
          <DataComponent />
        </Suspense>
      );
    }
    
    

    Suspense를 사용하여 DataComponent의 로딩 상태를 관리하고, 로딩 중에는 대체 UI를 표시합니다.


    7. 개발자 도구 개선

    리액트 18에서는 개발자 도구가 업데이트되어 컴포넌트의 수명 주기, 상태 변화, 성능 병목 현상 등을 더욱 상세하게 분석할 수 있게 되었습니다. 이를 통해 디버깅과 최적화 작업이 용이해졌습니다.