개념
배칭(batching)은 업데이트 대상이 되는 상태값들을 하나의 그룹으로 묶어서 한번의 리렌더링에 업데이트가 모두 진행될 수 있게 해주는 것을 의미한다. 한 함수 안에서 setState(업데이트)를 아무리 많이 호출시키더라도 리렌더링은 단 한번만 발생한다.
나오게 된 배경
이전부터 리랜더링과 관련해서 react-17v에서 이벤트 핸들러 내부에서 발생하는 상태 업데이트만 배치처리를 지원했다. 하지만 이벤트 핸들러 내부에 fetch()등 과 같은 콜백을 받아 처리하는 메소드가 존재할 경우 내부의 콜백이 모두 완료된 후에는 Automatic Batching이 처리되지 않았다. 그리고 react-17v에서 업데이트가 동기적으로 일어나지 않았다.
이전 버전과 최신 버전의 비교
1) React-17v
import React, { useState } from "react";
import "./App.css";
function App() {
// 2가지의 상태 존재
const [number, setNumber] = useState(0);
const [boolean, setBoolean] = useState(false);
// 하나의 핸들러에 2가지 상태를 업데이트
const onClickCreateNumber = () => {
setNumber((prev) => prev + 1);
setBoolean((prev) => !prev);
};
console.log("리렌더링");
return (
<>
<div>{number}</div>
<button onClick={onClickCreateNumber}>button</button>
</>
);
}
export default App;
-> 버튼을 클릭시 함수 onClickCreateNumber가 작동된다. 하나의 핸들러에 2가지 상태 업데이트가 이루어져야 하지만, 한가지 상태 업데이트만 이루어진다.
2) React-18v
import React, { useState } from "react";
import "./App.css";
function App() {
const [number, setNumber] = useState(0);
const [boolean, setBoolean] = useState(false);
const onClickCreateNumber = () => {
// fetch()를 활용해서 콜백함수 내부에서 여러개의 상태 업데이트
fetch("https://jsonplaceholder.typicode.com/posts/1").then((response) => {
setNumber((prev) => prev + 1);
setBoolean((prev) => !prev);
});
};
console.log("리렌더링");
return (
<>
<div>{number}</div>
<button onClick={onClickCreateNumber}>button</button>
</>
);
}
export default App;
→ 버튼 한 번 클릭시 리랜더링이 한번 이루어지며, 두가지 상태 업데이트가 된다.
이벤트 핸들러 내부에서 2가지 상태를 활용할 경우
import React, { useState } from "react";
import "./App.css";
function App() {
const [number, setNumber] = useState(0);
const [boolean, setBoolean] = useState(false);
const onClickCreateNumber = () => {
// 핸들러 내부에서 상태 업데이트 (콜스택)
setNumber((prev) => prev + 1);
// fetch() 콜백함수 내부에서 상태 업데이트 (태스트 큐)
fetch("https://jsonplaceholder.typicode.com/posts/1").then((response) => {
setBoolean((prev) => !prev);
});
};
console.log("리렌더링");
return (
<>
<div>{number}</div>
<button onClick={onClickCreateNumber}>button</button>
</>
);
}
export default App;
- 버튼 클릭 1번당 리렌더링이 2번 발생하고 있다. 일반적인 상태 업데이트 + 콜백함수 내부에서 상태 업데이트를 진행할 경우 Automatic Batching는 동시 사용 불가하다.
- 콜백함수인 fetch()나 setTimeout()안에 여러가지 상태 업데이트를 넣어서 해야 한다.
- Automatic Batching은 지원 범위를 기존 콜스택에서 태스크 큐까지 확장한 것이다. react-18v에서 setTimeout이나 fetch 등의 Web API에 대해서는 재렌더링을 배치로 관리한다. 그래서 어떤 함수를 실행하든 재랜더링을 배치로 관리한다.
사용
버전 18부터는 ReactDOM.render 대신, createRoot 메서드로 어플리케이션을 감쌀 DOM 요소를 지정해야 Automatic Batching이 사용가능하다.
// React-17v
const container = document.getElementById("root");
const root = ReactDOM.createRoot(container)
그리고 컨테이너의 자식으로 어플리케이션을 렌더링합니다.
// React-18v
const container = document.getElementById("root");
const root = ReactDOM.createRoot(container)
root.render(<App/>);
ReactDOM.flushSync()
기존처럼 비동기 작업 내에서 배치 업데이트를 사용하지 않으려면 ReactDOM.flushSync() 메서드를 활용할 수 있다. 이전처럼 비동기 함수 내의 중첩된 상태 업데이트에 배치가 필요하지 않을 시, flushSync 함수를 통해 이전 버전처럼 동작하도록 할 수 있습다.
import React, { useState } from "react";
// flushSync() import
import { flushSync } from "react-dom";
import "./App.css";
function App() {
const [number, setNumber] = useState(0);
const [boolean, setBoolean] = useState(false);
const onClickCreateNumber = () => {
// flushSync() 활용
flushSync(() => {
setNumber((prev) => prev + 1);
});
flushSync(() => {
setBoolean((prev) => !prev);
});
};
console.log("리렌더링");
return (
<>
<div>{number}</div>
<button onClick={onClickCreateNumber}>button</button>
</>
);
}
export default App;