diff --git a/contents/react/aboutUseEffect.mdx b/contents/react/aboutUseEffect.mdx
index 3ddfb50..319cba4 100644
--- a/contents/react/aboutUseEffect.mdx
+++ b/contents/react/aboutUseEffect.mdx
@@ -49,10 +49,8 @@ const Component = ({ items }) => {
`useEffect`는 읽고 이해하기 쉽지 않습니다.
문제의 경우 단순하지만 컴포넌트가 복잡해질수록 코드를 변경할 때 신경 쓸 부분이 많아집니다.
-
- 상태 변경에 대응해 어떤 로직을 실행해야 할 경우, 무의식적으로 useEffect를
- 사용하는 것은 많은 리액트 개발자가 저지르는 실수입니다.
-
+상태 변경에 대응해 어떤 로직을 실행해야 할 경우, 무의식적으로 useEffect를
+ 사용하는 것은 많은 리액트 개발자가 저지르는 실수입니다.
diff --git a/contents/react/automaticBatching.mdx b/contents/react/automaticBatching.mdx
new file mode 100644
index 0000000..873623a
--- /dev/null
+++ b/contents/react/automaticBatching.mdx
@@ -0,0 +1,180 @@
+---
+id: qwf0tk47bp5s
+title: 리렌더링 횟수는?
+date: 2023-11-04
+tags:
+ - React
+ - Automatic Batching
+ - React 18
+relatedLinks:
+ - https://immigration9.github.io/react/2021/06/12/automatic-batching-react.html
+ - https://react.dev/blog/2022/03/08/react-18-upgrade-guide#automatic-batching
+ - https://github.com/reactwg/react-18/discussions/21
+questionType: 주관식
+question:
+ - React 18 + createRoot 환경에서
+ - onClick 이벤트 발생 시 컴포넌트의 리렌더링 횟수는?
+ - "const Component = () => {\n\tconst [state1, setState1] = useState(true);\n\tconst [state2, setState2] = useState(true);\n\tconst onClick = async () => {\n\t\tsetState1((curr) => !curr);\n\t\tsetState2((curr) => !curr);\n\t\tconst state = await getServerState();\n\t\tsetState1(state);\n\t\tsetState2(state);\n\t\tsetTimeout(() => {\n\t\t\tsetState1((curr) => !curr);\n\t\t\tsetState2((curr) => !curr);\n\t\t}, 100);\n\t\tsetTimeout(() => {\n\t\t\tsetState1((curr) => !curr);\n\t\t\tsetState2((curr) => !curr);\n\t\t}, 100);\n\t};\n};
"
+answer:
+ - "3"
+level: 3
+category: "react"
+description:
+ - 리액트는 불필요한 리렌더링을 줄이기 위해 여러 개의 state 업데이트를 하나로 묶어요.
+ - React 18 부터는 Automatic batching을 지원해요.
+ - 리액트 이벤트 핸들러가 아니더라도 배칭이 가능해요.
+---
+
+# batching?
+
+배칭이란 리액트가 더 나은 성능을 위해 여러 상태 업데이트를 하나로 묶어 리렌더링 하는 것을 의미합니다.
+
+```javascript
+const Component = () => {
+ const [state1, setState1] = useState(true);
+ const [state2, setState2] = useState(true);
+
+ const onClick = () => {
+ setState1(false); // 리렌더링 전
+ setState2(true); // 리렌더링 전
+ // **핸들러 함수가 마무리되면 리렌더링
+ };
+
+ ...
+};
+```
+
+리액트는 상태 변경에 대응해 리렌더링합니다.
+
+하지만 위 경우, `setState1`과 `setState2`에 모두 반응하여 두 번 리렌더링한다면 성능적으로 좋지 않겠죠?
+
+또한 절반만 완료된 업데이트가 반영되어 의도하지 않은 상태 조합을 가질 수도 있습니다.
+
+이를 위해 리액트 팀은 `batching`이라는 개념을 도입했습니다.
+
+동시에 일어나는 상태 변경을 한 번에 처리해 렌더링 횟수를 최적화합니다.
+
+
+하지만 React 17까지는 이벤트 핸들러 밖에서 발생하는 업데이트에 대해서는 배칭하지 않았습니다.
+
+
+
+
+
+
+```javascript
+const Component = () => {
+ const [state1, setState1] = useState(true);
+ const [state2, setState2] = useState(true);
+
+ const onClick = () => {
+ fetchiApi().then(() => {
+ // onClick 핸들러가 마무리 된 후에 실행
+ // fetchApi의 콜백으로 동작
+ setState1(false); // 리렌더링
+ setState2(true); // 리렌더링
+ })
+ };
+
+ ...
+};
+```
+
+위 예시처럼, `onClick` 함수가 종료된 후에 실행되는 비동기 요청에 대한 콜백이나,
+
+`setTimeout`, `Promise` 혹은 네이티브 이벤트에 대한 핸들러 내부의 업데이트는 배칭되지 않았습니다.
+
+리렌더링이 두 번 발생하고 있죠.
+
+이를 해결하기 위해 React 18에서 `Automatic batching`이 소개됩니다.
+
+# Automatic batching
+
+React 18의 `createRoot`로 생성된 루트 내의 모든 업데이트는 어디서 왔는가와 무관하게 자동으로 배칭됩니다.
+
+`timeout`, `Promise`등의 비동기 처리 콜백이나 외부(네이티브) 이벤트 핸들러에 대해서도 배칭이 동작합니다.
+
+리액트 팀은 이를 `Automatic batching`이라고 소개했습니다.
+
+신기한 점은 자동 배칭이 짧은 tick 동안 쌓여있는 업데이트들을 묶어 실행한다는 것입니다.
+
+
+
+
+```javascript
+const Component = () => {
+ const [state1, setState1] = useState(true);
+ const [state2, setState2] = useState(true);
+ const onClick = async () => {
+ setState1((curr) => !curr);
+ setState2((curr) => !curr); // 리렌더링
+ const state = await getServerState(); // 비동기 데이터 waiting
+ setState1(state);
+ setState2(state); // 리렌더링
+ // -------- 한 번에 리렌더링 --------- //
+ setTimeout(() => {
+ setState1((curr) => !curr);
+ setState2((curr) => !curr);
+ }, 100);
+ setTimeout(() => {
+ setState1((curr) => !curr);
+ setState2((curr) => !curr);
+ }, 100);
+ // ------------------------------- //
+ };
+};
+```
+
+퀴즈 정답은 3 입니다.
+
+핸들러 내부의 업데이트는 배칭 처리를 할 수 있다고 쳐도, 언제 끝날 지 모르는 외부 업데이트를 어떻게 배치 처리 하는지 신기하지 않나요?
+
+내부적으로 타이머를 돌리는건지, 동작원리가 궁금해져 찾아본 결과 리액트 팀의 답변을 찾았습니다.
+
+
+ "실질적으로 말하자면, React가 '조금 기다린다'는 것을 의미합니다 ("작업 또는 마이크로 태스크가 끝날 때까지"인 경우 기술 용어). 그러면 React가 화면을 업데이트합니다." + ++ + +간단하게 리액트가 `batching` 중일시 업데이트를 큐에 쌓아두고 마이크로 태스크 큐가 비면 배칭된 업데이트를 실행한다는 식의 답변을 확인했습니다. + +위의 코드를 테스트해보면 100ms의 `setTimeout`이 두 개 돌아가고 있는데도 배칭되어 실행됩니다. + +재미있는 테스트를 해보겠습니다. + +```javascript +const Component = () => { + const [state1, setState1] = useState(0); + const [state2, setState2] = useState(0); + console.log("rendered", state1, state2) + const onClick = () => { + // setTimeout1 + setTimeout(() => { + setState1(1); + setState2(1); + }, 100); + // setTimeout2 + setTimeout(() => { + setState1(2); + setState2(2); + }, 101); + }; +}; +``` + +위 테스트의 결과는 어떨 것 같나요? + +1ms 차이를 두고 배치 처리가 되는지 테스트하는 코드입니다. + +결과는 일관적이지 않습니다. + +`setTimeout1`과 `setTimeout2`가 동시에 실행되기도, 묶여 실행되기도 합니다. + +DOM 페인팅이라던지 어떤 이벤트들이 마이크로태스크큐에 남아있다면 묶여 처리되는걸로 예상됩니다. + +리액트 팀의 답변 이해를 돕는 테스트랄까요. + +재미있죠? \ No newline at end of file