Tearing은 같은 상태를 읽는 여러 컴포넌트가 한 화면 안에서 서로 다른 시점의 값을 보여 주는 UI 불일치다. 화면이 "찢어진" 것처럼 보인다고 해서 붙은 이름이다(그래픽스에서 반쯤 그린 프레임이 보이는 현상에서 따왔다).
렌더 시작: store = 0
CounterA 렌더 → 0 읽음
(React가 잠시 양보한 사이 store = 1로 변경)
CounterB 렌더 → 1 읽음 → 화면에 0과 1이 동시에- React 17까지는 거의 없었다. 렌더가 동기라 한 번 시작하면 끝까지 돌았고, 그 사이에 값이 바뀔 틈이 없었다
- React 18의 동시성 렌더링에서 생길 수 있게 됐다. 렌더 도중 브라우저에 제어권을 넘기는 사이 외부 값이 바뀔 수 있기 때문이다
- React 밖의 상태에서 생긴다: Redux·Zustand·MobX 같은 외부 스토어,
window값, 직접 만든 전역 객체.useState처럼 React가 관리하는 상태는 렌더 동안 같은 스냅샷이 보장된다 useEffect로 스토어를 구독해setState로 옮겨 담는 옛 방식은 이 틈을 막지 못한다- 해결: useSyncExternalStore가 렌더 동안 하나의 스냅샷(Snapshot)만 보게 하고, 커밋 직전에 값이 바뀌었으면 다시 렌더한다. 결과는 전부 옛 값이거나 전부 새 값 둘 중 하나다
일관된 스냅샷을 보장하는 문제는 DB(Database)의 격리 수준(ACID)이나 분산 시스템의 최종 일관성와 같은 계열의 고민이다.