[React] 기초 정리 (2) React 18 - Automatic Batching

noodle·2023년 12월 13일

react-basic

목록 보기
1/2
post-thumbnail

React에서는 set함수를 통해 state를 변경한다. state가 변경되면 리렌더링이 발생한다.

React에서는 성능 최적화를 위해 여러 state를 한 번에 모아서(Batching) 처리한다. 이렇게 하면 불필요한 리렌더링을 줄여 애플리케이션의 성능을 향상시킬 수 있기 때문이다.

React 18 - Automatic Batching

React 18 버전 부터 자동 배치, 이른바 Automatic Batching이 일어난다.
여러 상태 업데이트를 하나의 리렌더링으로 묶어서 성능을 향상시키는 방법을 의미한다.

그래서 setState 함수를 호출해서 state를 변경해도, 그 변경이 즉시 반영되지 않는다.

batch 하기 위해서는 함수는 비동기로 처리되어야 한다.

리액트 17 이하의 과거 버전의 경우

이벤트 핸들러 내부에서는 자동 배치가 이뤄지고 있지만, Promise, setTimeout 같은 비동기 이벤트에서는 자동 배치가 이뤄지고 있지 않았다. 즉, 동기와 비동기 배치 작업에 일관성이 없음.

리액트 18의 경우

루트 컴포넌트를 createRoot를 사용해 만들면 모든 업데이트가 배치 작업으로 최적화할 수 있게 됐다.

import "./index.css";

import App from "./App.jsx";
import ReactDOM from "react-dom/client";

ReactDOM.createRoot(document.getElementById("root")).render(<App />);

루트 요소를 document.getElementById("root")로 가져와서, ReactDOM.createRoot를 활용해 렌더링하도록 설정했다. 이렇게 하면 자동 배치가 활성화되어 리액트가 동기, 비동기, 이벤트 핸들러 등에 관게 없이 렌더링을 배치로 수행하게 된다.


이 코드를 실행하는 경우 17 버전에서는 2번, 18 버전에서는 한번만 update가 일어난다.

import { Profiler, useCallback, useEffect, useState } from "react";

const sleep = (ms) => {
  return new Promise((res) => setTimeout(res, ms));
};

export default function Test() {
  const [count, setCount] = useState(0);
  const [flag, setFlag] = useState(false);

  const callback = useCallback((id, phase, commitTime) => {
    console.group(phase);
    console.table({ id, phase, commitTime });
    console.groupEnd();
  }, []);

  useEffect(() => {
    console.log("rendered!");
  });

  function handleClick() {
    sleep(3000).then(() => {
      setCount((c) => c + 1);
      setFlag((f) => !f);
    });
  }
  
  return (
    <Profiler id="react18" onRender={callback}>
      <button onClick={handleClick}>Next</button>
      <h1 style={{ color: flag ? "blue" : "black" }}>{count}</h1>
    </Profiler>
  );
}

react18 버전에서의 automatic batching
react18 버전에서의 automatic batching

0개의 댓글