React 18 Automatic Batching: 렌더링 성능 향상의 무기

@JasonLee · June 01, 2023 · 5 min read

서론

React 18 에서는 Automatic Batching 이라는 기능이 추가되었다. 이 기능은 이전 버전의 Batching 보다 향상된 성능을 자랑한다. 본고에서는 기본적으로 Batching 이란 무엇인지, 그리고 이 기능을 사용하여 어떠한 효과를 가져오는지 실제 예시를 통해 알아보도록 하겠다.


본론

상태 변경과 렌더링: React의 핵심

React는 선언적 UI 라이브러리로, 우리가 어떤 화면을 보여줘야 하는지만 명시하면, React가 상태의 변경과 UI의 렌더링을 어떻게 처리할지 알아서 해준다. 예를 들어, setState 함수를 사용해서 상태를 변경하면, React는 그 상태에 맞춰 UI를 재렌더링해 준다.

그런데, 상태가 여러 번 변경되면 어떻게 될까? 모든 상태 변경마다 UI를 재렌더링한다면, 불필요하게 많은 렌더링이 발생하게 될 것이다. 이런 경우에 React는 Batching이라는 기능을 통해 여러 상태 변경을 한 번에 처리한다.

Batching 이란?

Batching 이란 React 에서 state 의 변화가 일어날 때, render 함수가 여러번 호출되는 것을 방지하기 위해 state 의 변화가 일어난 후, render 함수를 한번만 호출하는 것을 말한다. 이를 통해 불필요한 render 함수의 호출을 방지하여 렌더링 성능을 향상시킬 수 있다.

조금 더 풀어서 말해보자면, Batching은 여러 개의 작업을 한 번에 묶는 것을 말한다. 예를 들어, 사무실에서 문서를 프린트할 때, 문서 한 장, 한 장을 따로따로 프린트하는 대신에 여러 문서를 한 번에 프린트하는 것과 비슷하다. React에서도 이와 비슷한 원리로 동작하는데, 여러 개의 상태 변경을 한 번에 묶어서 처리한다는 점이다.

Batching 예시

import { useState } from 'react';

const App = () => {
  const [count, setCount] = useState(0);

  const onClick = () => {
    setCount(count + 1); // re-renderering 이 일어나지 않는다.
    setCount(count + 1); // re-renderering 이 일어나지 않는다.
    // 마지막에 re-rendering 이 발생한다. (batching).
  };

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

위 예시 코드를 주석을 신경쓰지 않고 원초적으로 보자면, onClick 함수가 실행되면 setCount동기적 으로 실행되어, 기존

React Component 는 상태가 변경되면 re-rendering 이 일어난다.

말에 따라 총 2번의 re-rendering 이 발생할 것이라 생각할 수 있다. 하지만, 첫번째로 useState 훅의 setCount 함수는 동기적 으로 실행되지 않는다.

두밴쩌로 React 의 Batching 에 의해 onClick 함수 내의 두번의 setCount 로 인해 상태가 각기 변경되더라도, 마지막에 한번의 re-rendering 이 일어난다.

React 18 이전까지는, batched updates 오로지 React event handlers 내부에서만 작동했다. promises, setTimeout, native event handlers 에서는 batching이 일어나지 않았다.

Automatic Batching 이란?

Automatic BatchingReact 18 에서 새롭게 추가된 기능으로서 Batching 을 자동으로 처리해주는 기능이다. 이전 Batching 과 다르게, 어디에서 상태가 변경되던지 상관없이 Batching 이 일어난다.

promises, setTimeout, native event handlers 등에서도 모두 Batching 이 일어난다.

Batching 을 피하고 싶다면?

하지만, 명시적으로 Batching 이 동작하길 원하지 않고, 매 상태변화 마다 DOM update 가 일어나야 하는 상황 또한 존재할 수 있다. 해당 케이스에서는 ReactDOM.flushSync() 를 사용하여 명시적으로 Batching 을 피할 수 있다.

import { useState } from 'react';
import { flushSync } from 'react-dom';

const App = () => {
  const [count, setCount] = useState(0);

  const onClick = () => {
    flushSync(() => {
      setCount(count + 1); 
    });
    // re-renderering 이 일어난다.

    flushSync(() => {
      setCount(count + 1);
    });
    // re-renderering 이 일어난다.
  };

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

결론

React의 Batching은 상태 변경을 최적화하고 렌더링 성능을 향상시키는 중요한 기능이다. 이를 이해하고 활용하면, 더욱 효율적인 React 애플리케이션을 만들 수 있을 것이다.

@JasonLee
Hello :) I'm Jason Lee and currently focusing on React.js.