Expo UI (@expo/ui)
@expo/ui は React から本当のネイティブ UI をレンダリングします。iOS では SwiftUI、Android では Jetpack Compose です。また、RN コミュニティ UI ライブラリからの移行のためのドロップイン代替も提供します。
これらの手順は最新の 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>Café name</Text>
<Text>Address</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のルートからインポートします。1つのコンポーネントツリーが、単一のソースから iOS、Android、Web で変更なしで動作します(Android では Compose、iOS では SwiftUI、Web ではreact-native-web/react-dom)。プラットフォームファイルの分割は不要です。→./references/universal.md -
プラットフォーム固有(SwiftUI / Jetpack Compose)
@expo/ui/swift-uiまたは@expo/ui/jetpack-composeからインポートします。ユニバーサルレイヤーに必要なコンポーネントやモディファイアがない場合、またはプラットフォーム固有の動作や最適化が必要な場合にのみ使用します。欠点: 2つのツリーを記述し、.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ファイルで分離するか(app/内には決して配置しないでください — Expo Router はルートファイルのプラットフォーム拡張子をサポートしていません)、通常のルートファイルで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> からインポートできます。これは既存の依存関係を置き換えるための移行補助パスであり、上記のユニバーサル vs プラットフォームの判断のステップではありません。→ ./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 スキルを読み込み、その評価候補フローに従ってください。