React Native Fabric: React 계산은 어떻게 실제 화면이 되는가
React가 계산한 UI를 실제 Android·iOS 화면에 반영하는 세 책임을 구분하고, 측정 시점 때문에 안내 상자가 잠깐 잘못된 위치에 나타나는 문제를 교정한다.
목차
표준·구현·측정·해석 표시는 무엇인가요?
- 표준웹 표준이나 언어 명세가 정한 동작
- 구현특정 기술이나 브라우저가 실제로 구현한 동작
- 측정명시한 환경에서 직접 실행해 관찰한 결과
- 해석앞선 근거에서 도출한 설계 판단
- 미확인아직 공식 근거나 재현 결과를 확인하지 못한 내용
30초 요약
Fabric 렌더러는 React 계산을 Android·iOS 화면에 바로 명령하지 않는다.
Render → C++ React Shadow Tree를 준비
Commit → 위치·크기를 계산하고 다음 트리를 확정
Mount → 이전·다음 트리의 차이를 실제 호스트 뷰에 적용측정한 크기나 위치로 같은 화면을 다시 배치해야 한다면 일반 Effect보다 useLayoutEffect에서
호스트 뷰를 측정한다. 이때 프레임은 사용자가 보는 화면을 한 번 갱신하는 단위다. 공통
파이프라인이 같아도 텍스트 측정과 최종 Mount 결과는 Android와 iOS에서 각각 확인한다.
이 글을 관통하는 상황: 안내 상자가 잠깐 화면 위로 붙는다
결제 버튼 바로 아래에 안내 상자를 놓는 화면을 만든다고 하자. 아래 App.tsx는 버튼의 화면상
위치와 높이를 측정해 안내 상자의 top을 정한다. measure가 전달하는 pageY는 화면 기준 세로
위치이고 height는 측정한 호스트 뷰의 높이다.
import { useEffect, useRef, useState } from 'react'
import { Pressable, StyleSheet, Text, View } from 'react-native'
export default function App() {
const targetRef = useRef<View>(null)
const [showTip, setShowTip] = useState(false)
const [tipTop, setTipTop] = useState(0)
function handleToggle() {
if (!showTip) setTipTop(0)
setShowTip(value => !value)
}
useEffect(() => {
if (!showTip) return
targetRef.current?.measure((_x, _y, _width, height, _pageX, pageY) => {
setTipTop(pageY + height + 8)
})
}, [showTip])
return (
<View style={styles.screen}>
<View ref={targetRef} collapsable={false}>
<Pressable style={styles.button} onPress={handleToggle}>
<Text style={styles.buttonText}>결제 안내 보기</Text>
</Pressable>
</View>
{showTip ? (
<View style={[styles.tip, { top: tipTop }]}>
<Text>결제 전에 배송지를 확인하세요.</Text>
</View>
) : null}
</View>
)
}
const styles = StyleSheet.create({
screen: { flex: 1, padding: 24, paddingTop: 160 },
button: { backgroundColor: '#222', padding: 16 },
buttonText: { color: '#fff' },
tip: {
position: 'absolute',
left: 24,
right: 24,
backgroundColor: '#ffe9a8',
padding: 12,
},
})이 예제의 collapsable={false}는 1편에서 본 것처럼 측정할 래퍼 호스트 뷰가 최적화로 없어지지
않게 한다. 미리 준비한 가상 증거인 fixture에서는 루트 screen이 화면 좌표의 시작점에 있다고
가정해 pageY를 같은 부모 화면의 절대 위치에 사용한다. 앱의 React 루트가 다른 네이티브 뷰 안에 들어간다면 좌표계를
먼저 맞춰야 한다. 이 글에서 비교할 문제는 측정 대상이나 좌표 변환이 아니라 측정 시점이다.
fixture가 각 Mount와 Effect 실행을 기록했다고 하자. 이것은 React Native의 고정 로그가 아니다.
기록을 보기 전에 예측한다.
showTip이true가 된 첫 Render에서tipTop은 얼마인가?- 그 값으로 만든 안내 상자 트리가 먼저 Mount될 수 있는가?
measure결과로setTipTop을 호출하면 몇 번째 Render가 필요한가?
0ms Render A: showTip=true, tipTop=0
2ms Commit A: 안내 상자 top=0인 다음 트리 확정
4ms Mount A: 안내 상자를 top=0으로 적용
7ms 일반 Effect: 버튼 측정 결과 top=216
8ms Render B: showTip=true, tipTop=216
10ms Commit B와 Mount B: 안내 상자를 top=216으로 이동기기 부하와 프레임 시점에 따라 사용자가 중간 위치를 실제로 보는지는 달라질 수 있다. 하지만
첫 Mount에 top=0이 들어갔다는 사실은 안정적인 최종 위치만 반영한다는 계약이 없음을 보여 준다.
Fabric은 Render·Commit·Mount를 이어 준다
4편의 JSI는 JavaScript와 C++가 상호작용하는 기반이다. Fabric은 그 기반을 사용해 React 컴포넌트와 C++ Shadow Node를 연결하지만, JSI 자체와 같은 이름의 기능은 아니다.
Render는 다음 화면의 구조를 계산한다
state가 바뀐 업데이트에서는 모든 노드를 무조건 새로 만들지 않는다. 변경 경로의 Shadow Node를 복제하고 바뀌지 않은 부분은 재사용할 수 있다. 이 단계의 결과는 다음 플랫폼 화면을 위한 계산 구조이지 아직 사용자가 보는 Android View나 iOS UIView 변경 그 자체가 아니다.
Commit은 레이아웃과 다음 트리를 확정한다
대부분의 레이아웃 계산은 C++에서 이루어지지만 텍스트와 입력처럼 플랫폼 고유 크기가 필요한 컴포넌트는 Android·iOS가 제공하는 측정 함수의 도움을 받는다. 따라서 공통 스타일 입력이 같다는 사실만으로 양쪽 플랫폼의 모든 픽셀이 같다고 결론 내리지 않는다.
Mount는 계산된 차이를 실제 화면에 적용한다
1편의 View Flattening도 이 차이 계산 구간에 참여해 필요 없는 호스트 뷰 생성을 줄일 수 있다.
따라서 setShowTip(true) 한 줄을 플랫폼 뷰를 직접 움직이는 명령으로 해석하면 안 된다.
setShowTip(true)
→ React가 다음 element 계산
→ Fabric이 Shadow Tree 준비
→ Yoga가 위치·크기 계산, 다음 트리 확정
→ 이전·다음 트리 차이 계산
→ UI 스레드가 실제 호스트 뷰에 변경 적용측정이 필요한 UI는 Layout Effect에서 닫는다
useLayoutEffect는 React가 화면 변경을 확정한 뒤 일반 Effect보다 먼저 레이아웃을 읽고 필요한
상태 변경을 마칠 때 사용하는 Hook이다. Hook은 컴포넌트에서 React 기능을 사용하는 함수다.
관통 예제에서는 파일의 두 부분만 정확히 교체한다.
- import { useEffect, useRef, useState } from 'react'
+ import { useLayoutEffect, useRef, useState } from 'react'
- useEffect(() => {
+ useLayoutEffect(() => {
if (!showTip) return
targetRef.current?.measure((_x, _y, _width, height, _pageX, pageY) => {
setTipTop(pageY + height + 8)
})
}, [showTip])같은 fixture에서 기대할 교정 기록은 다음과 같다.
0ms Render A: showTip=true, tipTop=0
2ms Commit A: 안내 상자 top=0인 다음 트리 확정
3ms Mount A: 측정 가능한 호스트 뷰에 top=0 적용, 아직 다음 화면을 표시하기 전
4ms Layout Effect: 버튼 측정 결과 top=216, setTipTop(216)
5ms Render B와 Commit B: 안내 상자 top=216인 다음 트리 확정
6ms Mount B: 같은 화면 표시 전에 안내 상자를 top=216으로 다시 적용
7ms 사용자에게 표시된 첫 화면: 안내 상자 top=216이 기록도 실제 구현이 자동으로 출력하는 보장이 아니다. 검증할 성공 조건은 첫 화면 캡처부터
안내 상자가 버튼 아래에 있고 top=0인 중간 화면이 한 프레임도 기록되지 않는 것이다. Effect의
실행 횟수만 세지 말고 실제 Mount 결과를 Android와 iOS에서 각각 관찰한다.
공통 파이프라인과 플랫폼 결과를 나눠 검증한다
이 안내 상자는 다음 순서로 검증한다.
- Android emulator에서 안내 상자를 열고 첫 프레임부터 버튼 아래인지 기록한다.
- iOS simulator에서 같은 절차와 긴 글자·큰 글꼴 설정을 반복한다.
- 두 플랫폼에서 안내 상자를 닫았다 다시 열어 이전 측정값에 우연히 의존하지 않는지 확인한다.
- 실제 지원 화면 크기와 글꼴 크기 조합에서 잘림과 겹침이 없는지 확인한다.
이 순서와 위치 판단은 simulator·emulator에서 재현할 수 있다. 카메라·센서처럼 실제 하드웨어가 필요한 기능은 아니므로 이 글의 Fabric 단계 검증에 실기기를 필수 조건으로 두지 않는다. 다만 제품이 별도 실기기 화면 품질 기준을 갖고 있다면 그 지원 기기에서도 최종 결과를 확인한다.
같은 상황을 다시 진단한다
문제 안내 상자가 처음에는 top=0에 Mount되고 측정 뒤 버튼 아래로 이동함
잘못된 판단 setState가 Android·iOS 뷰를 그 자리에서 직접 움직이므로 Effect 시점은 무관함
관찰 첫 Mount 뒤 일반 Effect가 측정하고 두 번째 Render·Commit·Mount를 만듦
원인 실제 레이아웃에 의존하는 상태 갱신이 일반 Effect까지 늦어짐
행동 호스트 뷰 측정과 위치 갱신을 useLayoutEffect에서 수행
검증 양쪽 플랫폼의 첫 기록부터 최종 위치이며 top=0 중간 Mount가 노출되지 않음풀 리퀘스트에서는 다음을 확인한다.
- React Render 결과를 플랫폼 뷰 직접 변경 명령처럼 설명하지 않았는가?
- Commit의 레이아웃·트리 확정과 Mount의 실제 호스트 뷰 변경을 구분했는가?
- 측정 대상이 실제 호스트 뷰로 남고 최신 레이아웃을 읽는가?
- 측정 기반 UI가 첫 프레임부터 최종 위치에 있는가?
- Android와 iOS의 측정·최종 화면 결과를 각각 확인했는가?
기억할 문장은 짧다.
Fabric은 React 계산을 Shadow Tree, 레이아웃, 차이 적용 순서로 실제 화면에 옮긴다.
다음 글에서는 화면이 아닌 플랫폼 기능을 JavaScript에 노출하는 TurboModules의 책임을 살펴본다.
Active recall
기억에서 꺼내 보기
답을 쓰지 않아도 됩니다. 먼저 머릿속으로 답한 뒤 펼쳐서 정답·이유·흔한 오해를 비교하세요.
01컴포넌트 함수가 새 JSX를 반환하는 순간 Android View나 iOS UIView도 그 자리에서 바로 바뀔까?
정답
아니다. Fabric이 Shadow Tree 생성, 레이아웃 계산과 트리 확정, 차이 계산과 UI 스레드의 Mount를 거쳐 실제 호스트 뷰에 반영한다.
관련 설명 다시 읽기왜 그런가
React 계산 결과와 플랫폼 화면 변경 사이의 단계를 나눠야 중간 레이아웃과 측정 시점을 올바르게 조사할 수 있다.
선택한 상태와 다음 복습일은 이 브라우저에만 저장됩니다.
02Commit이 끝났다는 말은 Android·iOS 호스트 뷰 변경까지 모두 적용됐다는 뜻일까?
정답
아니다. Commit은 레이아웃을 계산하고 다음 Shadow Tree를 확정하며, Mount가 이전·다음 트리의 차이를 실제 호스트 뷰에 적용한다.
관련 설명 다시 읽기왜 그런가
React 공통 모델의 Commit과 React Native 문서가 구분하는 Mount를 같은 단계로 합치면 실제 화면 변경 시점을 잘못 읽는다.
선택한 상태와 다음 복습일은 이 브라우저에만 저장됩니다.
03호스트 뷰 크기로 안내 상자 위치를 정할 때 일반 Effect에서 측정해도 첫 중간 위치가 절대 생기지 않을까?
정답
그렇게 보장할 수 없다. 일반 Effect를 기다리는 동안 기본 위치를 가진 트리가 먼저 Mount될 수 있으므로, 최신 레이아웃 측정과 같은 프레임의 교정에는 useLayoutEffect를 사용한다.
관련 설명 다시 읽기왜 그런가
측정값이 필요한 UI는 측정 시점과 그 결과로 생기는 두 번째 상태 갱신까지 하나의 검증 흐름으로 본다.
선택한 상태와 다음 복습일은 이 브라우저에만 저장됩니다.
04공통 Fabric 단계가 같으면 한 플랫폼에서 맞는 안내 상자 위치를 다른 플랫폼에서도 그대로 보장할 수 있을까?
정답
아니다. 파이프라인은 공통이지만 텍스트 같은 일부 측정과 Mount 구현은 호스트 플랫폼에 의존하므로 Android와 iOS 결과를 각각 확인한다.
관련 설명 다시 읽기왜 그런가
공통 렌더러 구조와 플랫폼별 최종 픽셀 결과는 서로 다른 검증 범위다.
선택한 상태와 다음 복습일은 이 브라우저에만 저장됩니다.
출처와 검증 범위
아래 날짜는 링크를 마지막으로 열어 본 날입니다. 문서 상단의 검증일은 글의 설명과 적용 범위를 다시 확인한 날입니다.
- Render, Commit, and MountReact Native · 공식 문서 · 확인 2026-08-09
- Threading ModelReact Native · 공식 문서 · 확인 2026-08-09
- Cross-Platform Architecture GlossaryReact Native · 공식 문서 · 확인 2026-08-09
- Measuring the LayoutReact Native · 공식 문서 · 확인 2026-08-09
- useLayoutEffectReact · 공식 문서 · 확인 2026-08-09