2025년Archive
9월 15일
오늘 배운 것 (TIL)
flushSync
- React 18에서 도입된 함수로 React의 자동 배칭을 우회하여 상태 업데이트를 동기적으로 처리하도록 강제하는 기능
React의 기본 동작
- 성능 최적화를 위해 여러 상태 업데이트를 하나의 리렌더링으로 묶어서 처리하는데 React 18 부터는 이 배칭이 더욱 강화되어
setTimeout,Promise, 네이티브 이벤트 핸들러에서도 자동으로 배칭이 일어난다.
flushSync의 동작 원리
flushSync는 이러한 배칭을 중단시키고, 함수 내부의 상태 업데이트를 즉시 동기적으로 처리한다.
import { flushSync } from "react-dom";
function handleClick() {
flushSync(() => {
setCount((c) => c + 1);
});
// 여기서 DOM이 이미 업데이트됨
flushSync(() => {
setFlag((f) => !f);
});
// 여기서 또 다른 DOM 업데이트 발생
}주요 특징
- 동기적 실행: flushSync 내부의 업데이트는 함수가 끝나기 전에 즉시 DOM에 반영된다.
- Effect 실행: flushSync는 layout effects(useLayoutEffect)도 동기적으로 실행시키지만, 일반 effects(useEffect)는 여전히 비동기로 실행된다.
- 성능 영향: 배칭을 우회하므로 과도한 사용은 성능 저하를 일으킬 수 있다.
사용 사례
DOM 측정이 필요한 경우
function ScrollToBottom() {
const [items, setItems] = useState([]);
const listRef = useRef(null);
function addItem() {
flushSync(() => {
setItems((prev) => [...prev, newItem]);
});
// DOM이 즉시 업데이트되어 정확한 scrollHeight를 측정 가능
listRef.current.scrollTop = listRef.current.scrollHeight;
}
}포커스 관리
function TodoList() {
const [todos, setTodos] = useState([]);
const inputRef = useRef(null);
function addTodo() {
flushSync(() => {
setTodos((prev) => [...prev, newTodo]);
});
// 새로 추가된 input에 즉시 포커스
inputRef.current?.focus();
}
}주의사항
- 성능: flushSync는 React의 최적화를 우회하므로 꼭 필요한 경우에만 사용해야 한다.
- Concurrent Features: flushSync 내부에서는 Suspense, 전환(transitions) 등의 concurrent 기능들이 제대로 작동하지 않을 수 있다.
- Effect 타이밍: useEffect는 여전히 비동기로 실행되므로, 동기적 실행이 필요하다면 useLayoutEffect를 사용해야 한다.