본문 바로가기
카테고리 없음

Batching

by 잘먹는 개발자 에단 2024. 10. 4.

 

Batch "일괄"

Batching "일괄처리"

 

"Batching is when React groups multiple state updates into a single re-render for better performance."

배칭은 더 나은 성능을 위해서 리액트가 여러개의 상태를 한번의 리렌더링에 업데이트 하는 것을 이야기 한다.

- Dan Abramov React Developer 

 

- 단기간에 일어나는 상태변화를 매번 렌더링하지 않고, 일괄 처리한다.

- 리액트 이벤트 단위로 배칭이 발생한다. 

- 배칭은 리액트의 상태 값을 일정한 주기로 처리하는 작업. 이벤트로 인해 변경되는 점이 하나든 여러개든 일정한 주기에 맞춰서 다 같이 처리될 수 있도록하는 리액트의 내부기능.

 

상태값 변경 > 변경된 상태값을 중심으로 가상돔 생성 > 이 때 만든 가상돔을 현재의 최신 UI의 가상돔과 비교 

> 적용 > 새로운 돔에 맞춰서 ui 변경

 

- 상태값 변화를 렌더링하고(리액트에 알려주고) 조정하는 일은 리액트에서 사용하고 있는 Fiber의 도움을 받는다.

 

 

> 리액트 17까지는 프로미스가 사용된 코드를 배칭의 범위에 포함하지 못했다. 

const handleClick = async() => {
	await sleep(0); // promise
    
    const randomA = getRandomNumber();
    
    setA(randomA);
    setB(MAX - randomA);
}

리액트 17에서는 이 경우에 setA와 setB는 각각 따로 실행되게 된다. 배칭이 되지 않는다.

이 경우에 setState가 여러개가 들어가게 되면 성능이 크게 저하될 수 있다.

 

> 리액트 18에서는? 

- createRoot 함수를 사용해서 리액트 루트 컴포넌트를 초기화하면, 프라미스와 타이머도 같은 주기 내에서 배칭할 수 있다. 이를 [자동배칭]이라고 한다. 

 

 

근데 useEffect 의 경우에 안에서 setState를 사용하는 경우는 대부분 UI를 즉각적으로 업데이트하고 싶을 경우가 많다.

하지만 대부분의 경우, 의도대로 동작하지 않는다.

const [value, setValue] = useState(0);

useEffect(()=>{
	setValue(1);
    // value를 쓰면 1이 나올 거라고 생각하지만 0이다.
    console.log(value);
    setValue(2);
    // 배칭 때문이다.
},[])

 

> 그렇다면 배칭을 하고 싶지 않다면?

ReactDOM.flushSync()를 사용하면 배칭하지 않을 수 있다. 

import { flushSync } from "react-dom"; // Note: react가 아닌 react-dom이다

function handleClick() {
  flushSync(() => {
    setCounter((c) => c + 1);
  });
  // 이 과정이 끝났을 때 React는 DOM을 업데이트한 상태이다
  flushSync(() => {
    setFlag((f) => !f);
  });
  // 이 과정이 끝났을 때 React는 DOM을 업데이트한 상태이다
}