본문 바로가기
공부/리액트

[React 18] Batching 배칭

by 야옹아옹 2022. 12. 12.

🎉 배칭이란?

React가 더 나은 성능을 위해 여러 개의 state 업데이트하나의 리렌더링으로 묶는 것을 의미한다.

batch의 의미 자체가 일괄처리다.

🎉 리액트 배치 예시

하나의 클릭 이벤트 안에 두 개의 state 업데이트(setState)를 가지고 있다면 React는 이 작업들을 배칭하여 하나의 리렌더링으로 만든다.

아래 코드는 버튼을 누를 때 마다, count와 flag 상태가 변경되지만 리렌더링은 단 한번만 수행한다.

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

  function handleClick() {
    setCount((c) => c + 1); // 아직 리렌더링 하지 않는다
    setFlag((f) => !f); // 아직 리렌더링 하지 않는다
    // React는 이 함수가 끝나면 리렌더링을 한다 (이것이 배칭이다!)
  }

  return (
    <div>
      <button onClick={handleClick}>Next</button>
      <h1 style=>{count}</h1>
    </div>
  );
}

🎉 배칭의 장점

  • 불필요한 리렌더링을 줄이기 때문에 성능이 향상된다.
  • 컴포넌트가 반만 완료된 state를 렌더링 하는 것을 방지한다.

🎉 언제 배칭을 할 지 결정하기

React는 그 동안 업데이트에 대한 배칭을 언제 할 것인지 일관적이지 못했다.

React v17

React 17 버전에서는 Promise, setTimeout, native 이벤트 핸들러 등에서 발생하는 업데이트들은 배칭되지않았다.
React 이벤트 핸들러 내부에서 발생하는 업데이트만 배칭이 됬다.
// 리액트 이벤트 핸들러 예시 - deleteRow가 리액트 이벤트 핸들러다.
<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>

https://codesandbox.io/s/trusting-khayyam-cn5ct?file=/src/index.js 

 

trusting-khayyam-cn5ct - CodeSandbox

trusting-khayyam-cn5ct by gaearon using react, react-dom, react-scripts

codesandbox.io

따라서 위 코드의 경우 state 업데이트는 배칭되지않고, 두 개의 독립적인 업데이트를 수행한다.

🎉 자동 배칭이란?

React 18createRoot를 통해, 모든 업데이트들은 어디서 왔는 가와 무관하게 자동으로 배칭되게 됬다.

그래서 17에서 18로 버전업을 하는 경우 index.js의 root를 연결하는 코드 부분이 달라진다.

React 18 버전의 index.js 코드 createRoot

모든 업데이트는 자동 배칭 된다. 코드샌드박스 코드

const rootElement = document.getElementById("root");
// This opts into the new behavior!
ReactDOM.createRoot(rootElement).render(<App />);

React 17 버전 이전의 index.js 코드 render

자동으로 배칭되지않는다. 코드샌드박스 코드 - 18 버전이지만 render를 사용

const rootElement = document.getElementById("root");
// This keeps the old behavior:
ReactDOM.render(<App />, rootElement);

🎉 배칭을 하고 싶지 않다면?

만약 배칭을 하지않고 싶다면 ReactDOM.flushSync()를 사용해 배칭하지 않을 수 있다.

단, 성능이 저하 될 수 있기때문에 필요한 경우에만 작업을 수행해야한다.

🎉 직접 해본 배칭 테스트 코드

react 17 버전 배칭 테스트

 

ReactV17 batch - CodeSandbox

ReactV17 batch by 12Ahn22 using react, react-dom, react-scripts

codesandbox.io

react 18버전 배칭 테스트

 

ReactV18-batch - CodeSandbox

ReactV18-batch by 12Ahn22 using react, react-dom, react-scripts

codesandbox.io

🎉 정리

  • React는 리렌더링 성능을 위해 state가 변경되었다고 바로 리렌더링을 하지않는다.
  • state 업데이트들을 하나로 묶어 한 번에 리렌더링을 진행한다.
  • 이전에는 리액트 이벤트 핸들러 내부에 발생하는 업데이트들만 배칭이 됬지만, React 18버전에서는 모든 업데이트에 배칭을 적용했다.
  • 리액트18버전에서 배칭을 하기위해 createRoot를 사용한다. 그래서 index.js 부분 코드가 변경됨
  • 자동 배칭을 하고 싶지않다면 flushSync를 사용하면 된다. 단, 성능에 문제가 생길 위험이 있다.

🎉 참고 자료

https://immigration9.github.io/react/2021/06/12/automatic-batching-react.html

 

React 18: 렌더링 최적화를 위한 자동 배칭

Introduction

immigration9.github.io

https://github.com/reactwg/react-18/discussions/21

 

Automatic batching for fewer renders in React 18 · Discussion #21 · reactwg/react-18

Overview React 18 adds out-of-the-box performance improvements by doing more batching by default, removing the need to manually batch updates in application or library code. This post will explain ...

github.com

https://medium.com/swlh/react-state-batch-update-b1b61bd28cd2

 

React State Batch Update

Changing the state and how it affects the component renders

medium.com

 

🎉리뷰

전에 회사에서 18버전으로 올리는 이야기가 나왔을 때, 왜 index.js 부분이 변경됬나 했었는데 createRoot에 많은 새로운 기능이 들어가게 되서 그런것 같다.

자동 배칭을 사용하기 위해서 뿐만아니라, 여러가지가 createRoot랑 관련이 된 것 같다.

배칭을 찾아보면서 앞으로 리액트가 state를 재사용?하는 방향으로 발전할 것이라는 글을 봤는데 아마 이러한 작업을 위한 토대가 아닐까 생각한다.

댓글