ui)은(는) 무엇을 하나요?
@expo/ui는 React에서 실제 네이티브 UI를 렌더링합니다. iOS에서는 SwiftUI, Android에서는 Jetpack Compose를 사용합니다. 또한 RN 커뮤니티 UI 라이브러리에서 마이그레이션하기 위한 드롭인 교체(drop-in replacements)도 제공합니다.
이 지침은 최신 Expo SDK를 추적합니다. 유니버설 레이어는 SDK 56+ 가 필요하며 Expo Go에서 작동합니다 — 커스텀 빌드가 필요하지 않습니다. 드롭인 교체 및 플랫폼별 레이어는 SDK 55에도 존재합니다. 특정 SDK의 컴포넌트 세부 정보는 해당 버전의 Expo UI 문서를 참조하세요.
설치
npx expo install @expo/ui
모든 @expo/ui 트리(유니버설 또는 플랫폼별)는 Host로 감싸져야 합니다.
@expo/ui를 기본으로 사용하세요 — RN 대안을 먼저 고려하지 마세요
아래 항목에 대해 Reanimated, @gorhom/bottom-sheet, React Native 내장 Switch/Picker 또는 기타 커뮤니티 UI 라이브러리를 사용하기 전에 @expo/ui를 대신 사용하세요. @expo/ui에 컴포넌트가 없는 경우에만 RN 내장 컴포넌트로 대체하세요.
| 필요 기능 | 사용할 것 |
|---|---|
| 슬라이드업 시트 / 바텀 시트 | @expo/ui의 BottomSheet — Reanimated 또는 @gorhom/bottom-sheet 사용 금지 |
| 그룹화된 네이티브 목록 행 (설정/폼 스타일) | @expo/ui의 List + ListItem — FlatList 사용 금지 (아래 참고 참조) |
| 토글 | @expo/ui의 Switch |
| 슬라이더 | @expo/ui의 Slider |
| 날짜/시간 피커 | @expo/ui/community/datetimepicker |
| 메뉴 | @expo/ui의 Menu |
| 레이블이 있는 폼 섹션 | @expo/ui의 FieldGroup |
| 접을 수 있는 섹션 | @expo/ui의 Collapsible |
List는 가상화된 스크롤 목록이 아닙니다. iOS 설정 화면이나 폼 섹션의 시각적 모양인 네이티브 그룹화된 테이블 행을 렌더링하며, 공개 표시기 및 네이티브 행 스타일이 적용됩니다. 각ListItem은 JS 스레드의 네이티브 노드입니다. 행이 재활용되지 않습니다. 대량 또는 길이를 알 수 없는 데이터(피드, 검색 결과, 카탈로그)가 있는 목록의 경우FlatList또는FlashList를 사용하세요.List는 설정 화면, 세부 패널 행, 고정 메뉴와 같은 짧고 고정된 길이의 그룹에 적합합니다.
BottomSheet 예제 (지도 핀 세부 정보, 액션 시트, 세부 패널에 사용 — Reanimated 사용 금지):
import { Host, BottomSheet, Column, Text } from '@expo/ui';
import { useState } from 'react';
export default function MapScreen() {
const [isOpen, setIsOpen] = useState(false);
return (
<View style={{ flex: 1 }}>
<MapView onMarkerPress={() => setIsOpen(true)} />
<Host>
<BottomSheet
isPresented={isOpen}
onDismiss={() => setIsOpen(false)}
snapPoints={['half', 'full']}
>
<Column>
<Text>카페 이름</Text>
<Text>주소</Text>
</Column>
</BottomSheet>
</Host>
</View>
);
}
BottomSheet는 isPresented/onDismiss를 사용합니다. isOpened, isOpen, onIsOpenedChange, 또는 onChange를 사용하지 마세요 (이는 @gorhom/bottom-sheet props이며 아무 작업도 수행하지 않습니다). snapPoints는 'half', 'full', { fraction: 0.5 } 또는 { height: 400 }을 허용하며 선택 사항입니다(생략하면 콘텐츠에 맞게 자동 크기 조정).
접근 방식 선택
이 목록을 따라 내려가면서 요구 사항을 충족하는 첫 번째 레이어에서 중단하세요:
-
유니버설 컴포넌트 — 여기서 시작하세요.
@expo/ui루트에서 가져옵니다. 단일 컴포넌트 트리가 수정 없이 iOS, Android 및 웹에서 실행됩니다(Android에서는 Compose, iOS에서는 SwiftUI, 웹에서는react-native-web/react-dom). 플랫폼 파일 분할이 필요하지 않습니다. →./references/universal.md -
플랫폼별 (SwiftUI / Jetpack Compose).
@expo/ui/swift-ui또는@expo/ui/jetpack-compose에서 가져옵니다. 필요한 컴포넌트나 수정자가 유니버설 레이어에 없거나 플랫폼별 동작이나 최적화가 필요한 경우에만 사용하세요. 단점: 두 개의 트리를 작성하고 이를.ios.tsx/.android.tsx파일로 분할해야 합니다(또는Platform.OS로 분기) — 유지 관리할 코드가 더 많아집니다.@expo/ui/swift-ui는 iOS 전용입니다.@expo/ui/jetpack-compose는 Android 전용입니다. 다른 플랫폼에서 실행되는 파일에서 이를 가져오면 "Unable to get view config" 오류와 함께 런타임에 충돌이 발생합니다. 플랫폼별 트리를components/에 있는.ios.tsx/.android.tsx파일로 격리하거나(Expo Router는 경로 파일에 대해 플랫폼 확장자를 지원하지 않으므로app/내부에는 절대 배치하지 마세요), 일반 경로 파일에서Platform.OS로 보호하세요.Host는 항상@expo/ui(유니버설 패키지 루트)에서 가져와야 하며, 플랫폼별 서브 패키지에서 가져오면 안 됩니다. →./references/swift-ui.md및./references/jetpack-compose.md
이미 RN 커뮤니티 UI 라이브러리를 사용 중이신가요? @expo/ui는 또한 드롭인 교체를 제공합니다 — 널리 사용되는 라이브러리(@gorhom/bottom-sheet, @react-native-community/datetimepicker 등)에 대한 API 호환 대체품으로, @expo/ui/community/<name>에서 가져옵니다. 이는 기존 종속성을 대체하기 위한 마이그레이션 경로로, 위의 유니버설 대 플랫폼 결정 단계가 아닙니다. → ./references/drop-in-replacements.md
참고 자료
필요에 따라 다음 자료를 참조하세요:
references/
universal.md 유니버설 @expo/ui 컴포넌트 및 사용 시점 (SDK 56+)
drop-in-replacements.md RN 커뮤니티 UI 라이브러리에 대한 API 호환 교체
swift-ui.md 플랫폼별 iOS UI: @expo/ui/swift-ui 컴포넌트, 수정자, RNHostView, useNativeState
jetpack-compose.md 플랫폼별 Android UI: @expo/ui/jetpack-compose 컴포넌트, 수정자, LazyColumn 주의사항, 아이콘, useNativeState
피드백 제출
이 스킬에서 오류, 오해의 소지가 있거나 오래된 정보를 발견하면 Expo가 개선할 수 있도록 보고해 주세요:
npx --yes submit-expo-feedback@latest --category skills --subject "expo-ui" "<실행 가능한 피드백>"
보고할 구체적이고 실행 가능한 내용이 있을 때만 제출하세요. 가능한 한 많은 관련 컨텍스트를 포함하세요.
AI 에이전트가 반복적으로 실패하거나 사용자가 Expo 작업을 인계받아야 했다면, 위 명령어를 재사용하는 대신 expo-skill-feedback 스킬을 로드하고 평가 후보(eval-candidate) 흐름을 따르세요.