Automatic batching (자동 일괄 처리)
Batching이란? (batch : '일괄'이라는 의미)
리액트는 state 값이 변경되었을 때마다 해당 컴포넌트를 리랜더링하는데, 기본적으로 setState()는 리액트가 새 랜더 패스를 시작하고 이를 동기적으로 실행하고 반환하도록 한다. 이때 랜더링을 한 번에 하나씩 처리하는 것이 아닌 여러 setState() 호출 결과를 한번에 실행하여 최적화를 자동으로 적용하기도 하는데 이를 '랜더링 일괄처리(batching)'라고 말한다. batching 작업을 자동으로 실행함으로써 불필요한 리랜더링을 방지해준다.
function App() {
const [count, setCount] = useState(0);
const [flag, setFlag] = useState(false);
function handleClick() {
setCount(c => c + 1); // Does not re-render yet
setFlag(f => !f); // Does not re-render yet
// React will only re-render once at the end (that's batching!)
}
return (
<div>
<button onClick={handleClick}>Next</button>
<h1 style={{ color: flag ? "blue" : "black" }}>{count}</h1>
</div>
);
}
그렇다면 일괄처리는 리액트 18에 새로 등장한 기능일까? 정답은 아니다.
리액트 17 및 이전 버전에서 리액트는 onClick 콜백과 같은 리액트 이벤트 핸들러에서만 일괄 처리를 수행했다. setTimeout, await 이후 또는 일반 JS 이벤트 핸들러와 같은 리액트 이벤트 핸들러 외에서의 업데이트는 큐에 추가되지 않았으며 각각 별도의 리랜더링이 발생했었다.
그러나 리액트 18에서는 이제 단일 이벤트 루프 틱에 대기 중인 모든 업데이트의 "자동 일괄 처리"를 수행한다. 따라서 필요한 전체 랜더링 수를 줄일 수 있다.
예를 들어
const [counter, setCounter] = useState(0);
const onClick = async () => {
setCounter(0); // 패스1
setCounter(1); // 패스2
const data = await fetchSomeData();
setCounter(2); // 패스3
setCounter(3); // 패스4
};
리액트 17 혹은 이전 버전을 사용하면 위의 코드에서 패스1과 패스2를 일괄처리하고, await 이후 패스3과 패스4를 각각 처리해서 총 3번의 랜더 패스를 실행한다. 하지만 리액트 18을 사용하면 패스1과 패스2가 일괄처리되고 await 이후 패스3과 패스4를 일괄처리되어 총 2번의 랜더 패스를 실행하게 된 것이다.
리액트 18부터 createRoot( )를 통해 모든 업데이트들이 어디서 왔는가와는 무관하게 자동으로 배칭된다.
만약 batching을 원하지 않는 경우(예를 들어 state 변경 후 즉시 DOM으로부터 값을 가져오는 것)에는 ReactDOM.flushSync( )를 사용하여 배칭하지 않을 수 있다.
import { flushSync } from 'react-dom'; // Note: react-dom, not react
function handleClick() {
flushSync(() => {
setCounter(c => c + 1);
});
// React has updated the DOM by now
flushSync(() => {
setFlag(f => !f);
});
// React has updated the DOM by now
}
참고
Automatic batching for fewer renders in React 18 #21
React 18에서 추가된 Auto Batching 은 무엇인가?
'React' 카테고리의 다른 글
[React] state 최적화를 해보자 (랜더링 최적화, memoization) (0) | 2023.06.20 |
---|---|
[React] 리액트 State와 Hooks란 무엇인가? (0) | 2023.06.20 |
[React] react-router-dom v6 동작원리 (0) | 2023.06.16 |
[React] Code splitting, Lazy loading, Suspense (0) | 2023.06.12 |
[React] Virtual DOM(가상돔)과 Rendering(랜더링) (0) | 2023.06.11 |