rn-components-apis — guardrail for RN core components + platform APIs
The 5 rules (non-negotiable)
Pressablefor any touchable — neverTouchableOpacity/TouchableHighlight/TouchableWithoutFeedbackin new code.expo-imagefor any image — neverImagefromreact-native(no caching).@shopify/flash-listfor lists with > 20 items or unknown length — neverFlatListat scale.useWindowDimensions()hook in the component — neverDimensions.get('window')at module top-level (fails on rotation/foldables).Platform.select({ ios, android })for platform-specific styles or behavior — neverPlatform.OS === ...ternaries scattered across the file.
Quick decision tree
- "Which list primitive?" →
references/decision-tree.md(ScrollView/FlatList/FlashList/SectionList) - "Which touchable?" → always
Pressable. Seereferences/patterns.mdfor the canonical button pattern. - "How do I open an external URL / mail / phone?" →
references/patterns.md(Linking section) - "Keyboard avoidance pattern?" →
references/patterns.md(KeyboardAvoidingView + Android quirks) - "I need a map in this screen" →
references/maps-mapcn-rn.md(mapcn-rn, the ecosystem-first default: MapLibre/Mapbox RN + NativeWind). ⚠️ native modules → needs a dev build, not Expo Go. Recordstack.maps = "mapcn-rn"— and the renderer + provider, which are a licensing and native-dependency decision, not a detail (v2 separates the two axes). - "None of these core components feel native enough for this screen" → these are all RN primitives (a JS abstraction over both platforms). For real native controls instead — SwiftUI on iOS, Jetpack Compose on Android (grouped settings sections, native picker/slider, real sheets) — that's
@expo/ui, a different tool. Seern-styling/references/expo-ui.md(verified against@expo/ui@57.0.14on 2026-08-26) for the full breakdown; this skill's guidance still applies whenever you're usingView/Text/ScrollView/etc. as-is.
Common anti-patterns (NEVER do)
- ❌
<TouchableOpacity> →<Pressable> - ❌
<Image source={{ uri }} />fromreact-native→import { Image } from "expo-image" - ❌
<FlatList data={items}>for any list that may grow →<FlashList data={items}>(FlashList v2 auto-sizes — noestimatedItemSize) - ❌
const { width } = Dimensions.get('window')at module top — useuseWindowDimensions()inside the component - ❌
<KeyboardAvoidingView>without explicitbehaviorprop — broken on Android. UsePlatform.select({ ios: "padding", android: "height" })
Sources
- Course: codewithbeto.dev/rnCourse — "Components and APIs" module (paid, distilled from docs).
- Official: https://reactnative.dev/docs/components-and-apis
- Official: https://docs.expo.dev/versions/latest/sdk/image/
- Official: https://shopify.github.io/flash-list/
- Official: https://docs.expo.dev/versions/latest/sdk/ui/ (
@expo/ui— native alternative to these components; seern-styling/references/expo-ui.md)