"매 React 18+ 의 automatic batching 우회 — 즉시 synchronous flush 강제". 매 React 18 의 default 가 모든 update 를 batch — 매 일부 case (third-party DOM lib, scrollIntoView after state change, focus management) 에서 즉시 flush 필요. 매 escape hatch — 매 misuse 시 perf 손해.
매 핵심
매 왜 필요한가
React 18 automatic batching: 매 setState 매 promises, timers, native event 까지 batch.
Pre-batch read pattern: 매 setState 후 즉시 DOM read/manipulation 가정한 legacy code 매 깨짐.
Third-party libs: 매 d3, jQuery plugin, chart lib 의 imperative DOM 의 sync state 필요.
scroll after mount: 매 list 의 새 item 추가 후 scrollIntoView — batch 하면 DOM 미반영.
focus after state change: 매 modal open + input focus — batch 하면 input 가 not yet rendered.
매 동작
flushSync(callback) — 매 callback 안의 모든 update 를 sync flush, 매 반환 직후 DOM 업데이트 완료.
매 callback 외부의 다른 pending update 까지 함께 flush (warning 로그).
매 expensive — 매 break 의 batching benefit (multiple re-renders).
매 응용
List 추가 후 scrollIntoView (chat, log).
Modal open + auto-focus input.
d3/Canvas 의 React state → imperative draw.
Print preview, screenshot 의 specific state 보장.
Document.title sync update (browser tab 즉시 반영).
💻 패턴
Scroll to bottom — chat
import{flushSync}from'react-dom';functionChat() {const[messages,setMessages]=useState<string[]>([]);constcontainerRef=useRef<HTMLDivElement>(null);constaddMessage=(msg: string)=>{flushSync(()=>{setMessages(prev=>[...prev,msg]);});// 매 이 시점에 DOM 이미 update — scrollIntoView 가능
containerRef.current?.scrollTo({top: containerRef.current.scrollHeight,behavior:'smooth',});};return<divref={containerRef}>{messages.map(...)}</div>;}
Modal open + auto-focus
functionApp() {const[open,setOpen]=useState(false);constinputRef=useRef<HTMLInputElement>(null);constopenModal=()=>{flushSync(()=>setOpen(true));// 매 modal 의 input 가 rendered — focus 가능
inputRef.current?.focus();};return(<><buttononClick={openModal}>Open</button>{open&&<Modal><inputref={inputRef}/></Modal>}</>);}
Imperative Canvas / D3 sync
functionChart({data}:{data: number[]}){constsvgRef=useRef<SVGSVGElement>(null);const[renderedData,setRenderedData]=useState(data);useEffect(()=>{flushSync(()=>setRenderedData(data));// 매 React 의 SVG 업데이트 후 d3 manipulation
d3.select(svgRef.current).selectAll('rect').transition()...;},[data]);return<svgref={svgRef}>{/* React renders rects */}</svg>;}
Print / Screenshot — specific state
consthandlePrint=()=>{flushSync(()=>{setIsPrintMode(true);// 매 hide menu, expand all sections
});window.print();setIsPrintMode(false);// 매 normal flush, no need flushSync
};
List item 추가 후 measure
functionList() {const[items,setItems]=useState<Item[]>([]);constlastRef=useRef<HTMLLIElement>(null);constadd=(item: Item)=>{flushSync(()=>setItems(prev=>[...prev,item]));// 매 마지막 item 의 height 측정 가능
constheight=lastRef.current?.getBoundingClientRect().height;console.log('New item height:',height);};// ...
}
Document title sync
functionNotificationCenter({count}:{count: number}){constincrementBadge=()=>{flushSync(()=>setCount(c=>c+1));// 매 doc.title 즉시 update — browser tab 표시
document.title=`(${count+1}) Inbox`;};// ...
}// 매 alternative: useEffect 로 title sync — 더 idiomatic.
React 19 — useTransition 과 비교
const[pending,startTransition]=useTransition();// 매 startTransition: low priority, batched, interruptible
startTransition(()=>setBigList(newData));// 매 flushSync: high priority, sync, immediate
flushSync(()=>setBigList(newData));// 매 둘 다 같이 사용 X — 의미 충돌.
매 결정 기준
상황
Approach
List 추가 후 scrollIntoView
flushSync.
Modal open + focus
flushSync + ref.focus().
Document.title sync
useEffect (idiomatic) 또는 flushSync.
Performance optimization
useTransition (반대 방향).
Simple state update
매 plain setState (자동 batch).
기본값: 매 setState (batching). 매 imperative DOM 의 즉시 sync 필요할 때만 flushSync.
언제: chat scroll-to-bottom, modal auto-focus, third-party imperative DOM sync, list 추가 후 measure 의.
언제 X: 매 일반 state update (batch 가 더 빠름), useTransition 으로 충분한 case, 매 useEffect 로 처리 가능한 side effect.
❌ 안티패턴
모든 setState 에 flushSync: 매 batching benefit 소멸 — 매 perf 저하.
render 중 호출: 매 flushSync inside render — error. 매 event handler / effect 에서만.
async 안에서: 매 await fetch(); flushSync(() => setX()) — 매 동작하나 매 batching 의 의미 없음 (async 가 이미 micro-task break).
useEffect 대체로 사용: 매 flushSync 매 sync flush 강제 — useEffect 의 lifecycle 의 대체 X.
Suspense 의 children update: 매 Suspense boundary 의 sync flush 매 hydration mismatch 위험.
🧪 검증 / 중복
Verified (React docs flushSync, React 18 release notes, Dan Abramov 의 RFC).
신뢰도 A.
🕓 Changelog
날짜
변경
2026-05-08
Phase 1
2026-05-10
Manual cleanup — flushSync use-cases, scroll/focus patterns, useTransition 비교 추가