react-native-patterns
npx skills add https://github.com/dralgorhythm/claude-agentic-framework --skill react-native-patterns
Agent 安装分布
Skill 文档
React Native Patterns
Overview
Patterns for building maintainable React Native components. Covers touch interactions (Pressable), list rendering (FlashList), modal patterns (bottom sheets), accessibility, navigation, and RN-specific requirements that differ from web React.
For React web patterns (hooks, context, composition), see the react-patterns skill.
Workflows
Building an interactive screen:
- Set up SafeAreaView or apply safe area insets
- Use Pressable for all interactive elements (44pt minimum)
- Add haptic feedback on primary actions
- Use FlashList for lists, ScrollView for fixed content
- Implement bottom sheet for detail/modal views
- Add accessibility labels to all interactive elements
- Test on device for touch targets and scroll performance
Guidance
Pressable (not TouchableOpacity)
Pressable is the standard touch component. TouchableOpacity is deprecated.
Key principles:
- 44pt minimum touch target on all interactive elements
- Use
hitSlopto expand touch area beyond visual bounds:hitSlop={{ top: 8, bottom: 8, left: 8, right: 8 }} - Style feedback via
stylefunction:style={({ pressed }) => [pressed && { opacity: 0.7 }]} - Or use NativeWind:
className="active:opacity-70" - Add haptics on press for primary actions:
onPress={() => { Haptics.impactAsync(); doAction(); }}
Text-Only Strings Rule
React Native requires all visible text to be wrapped in <Text>:
â
<View><Text>Hello</Text></View>
â <View>Hello</View> // Crashes at runtime
This applies to conditional renders, string interpolation, and JSX expressions. Always wrap strings in Text.
ScrollView Patterns
Two className targets:
classNameâ outer container (flex, background)contentContainerClassNameâ inner content (padding, gap, alignment)
Use ScrollView for screens with fixed, non-dynamic content. Use FlashList for dynamic lists.
showsVerticalScrollIndicator={false} for cleaner visual when custom scroll indicators are used.
FlashList Patterns
High-performance list rendering:
estimatedItemSizeis required â estimate average item height in pointsrenderItemreceives{ item, index }â keep render function purekeyExtractorâ use unique string ID from datacontentContainerClassNameâ NativeWind styling for inner contentItemSeparatorComponentâ consistent spacing between itemsListEmptyComponentâ graceful empty state
Bottom Sheet as Modal
@gorhom/bottom-sheet replaces web modal dialogs:
- Define
snapPointsarray:['25%', '50%', '90%'] - Use
BottomSheetModalwithBottomSheetModalProviderfor imperative control BottomSheetScrollViewfor scrollable sheet contentBottomSheetBackdropfor press-to-dismiss overlay- Present:
bottomSheetRef.current?.present() - Dismiss:
bottomSheetRef.current?.dismiss()
expo-image Patterns
Use for all image display:
- Remote images:
source={{ uri: 'https://...' }} - Local images:
source={require('../assets/image.png')} - Blurhash placeholder:
placeholder="LKO2?U%2Tw=w]~RBVZRi}"for loading state contentFit="cover"for card thumbnails,"contain"for full imagestransition={300}for smooth fade-in on load
Accessibility
Required accessibility props for interactive elements:
| Prop | Purpose | Example |
|---|---|---|
accessibilityRole |
Semantic role | "button", "link", "image" |
accessibilityLabel |
Screen reader text | "Open settings" |
accessibilityHint |
Action description | "Opens the settings screen" |
accessibilityState |
Dynamic state | { selected: true, disabled: false } |
accessible |
Marks as accessible | Default true for Pressable |
Guidelines:
- All Pressable elements need
accessibilityLabel - Images need
accessibilityLabeldescribing content - Use
accessibilityRole="header"for screen titles - Toggle/checkbox: set
accessibilityState={{ checked: isChecked }} - Disabled elements:
accessibilityState={{ disabled: true }}
Chat-Forward Component Patterns
Demos use a chat-forward interface where the conversation thread is the primary UI.
Chat Screen Layout
Three zones:
- Header: Minimal â title, back nav, optional status. Uses safe area top inset.
- Message stream: FlashList or inverted ScrollView for the conversation. Agent and user messages alternate. Rich content is embedded within agent message components.
- Input bar: Text input pinned to bottom. Uses
KeyboardAvoidingView(iOS) orandroid:windowSoftInputMode="adjustResize". Safe area bottom inset for home indicator. Optional quick-action chips above the text field.
Message Bubble
Agent and user bubbles have distinct styling (alignment, color, shape):
- Agent bubble: Left-aligned, neutral background, can contain child components (cards, summaries, action buttons)
- User bubble: Right-aligned, accent background, text only
- Bubbles animate in with
FadeInDown.duration(300)on append
Inline Rich Card
Compact data card rendered as a child of an agent message bubble:
- Photo thumbnail (expo-image) + title + key metric + status badge
- Tappable â opens bottom sheet with full detail
- For card sets: horizontal
ScrollViewwithin the message, or vertical stack - Stagger animation:
FadeInDown.delay(index * 50).duration(300)
Summary Card
Running totals/status that updates as the conversation progresses:
- Shows aggregated state: Keep ($X), Sell ($Y), Donate ($Z), Progress (N%)
- Can be rendered as a sticky element above the input bar for persistent visibility
- Content crossfades on update (150ms timing)
Prompt Card
Agent suggestion with embedded action buttons:
- Text prompt + 1-3 action buttons inline
- Buttons are Pressable with 44pt targets, haptic on press
- After tap, the prompt card updates to show the confirmed action
- E.g., “Want me to find pickup options?” â [Yes] [Not now]
Comparison View
Before/after or side-by-side content within a message:
- Two expo-image instances with labels (Before / After)
- Optional delta annotation (e.g., “New scratch detected”)
Timeline View
Chronological event list rendered inline within an agent message:
- Compact: date + title + icon per event
- Expandable: tap to show detail (inline expand or bottom sheet)
- Vertical line connector between events
Notification Message
Proactive agent alert that appears as a new message in the thread:
- Distinctive styling (icon + emphasis color) to differentiate from regular agent messages
- Can contain inline action buttons
- E.g., “Storm season starts in 6 weeks. Your basement still shows moisture risk.”
Navigation from Components
Use Expo Router’s useRouter() hook:
router.push('/path')â navigate forward (adds to stack)router.replace('/path')â replace current screenrouter.back()â go backrouter.canGoBack()â check if back navigation possible- Pass params:
router.push({ pathname: '/detail/[id]', params: { id: '123' } })
Best Practices
- Always use
PressableoverTouchableOpacityorTouchableHighlight - Enforce 44pt minimum touch targets â use
hitSlopwhen visual is smaller - Wrap every visible string in
<Text>â no bare strings in JSX - Use
expo-imagefor all images (never RNImage) - Add
accessibilityLabelto every interactive element - Use
FlashListwithestimatedItemSizefor any list with >10 items - Use
contentContainerClassNamefor ScrollView/FlashList inner styling - Add haptic feedback sparingly â primary actions only
- Test touch targets on real device (simulator touch is imprecise)
Anti-Patterns
- Using
TouchableOpacity(deprecated â use Pressable) - Touch targets smaller than 44pt without
hitSlopcompensation - Bare strings without
<Text>wrapper (runtime crash) - Using RN
Imageinstead ofexpo-image(no caching, no blurhash) - Forgetting
estimatedItemSizeon FlashList - Using
FlatListfor large datasets (FlashList is faster) - Missing
accessibilityLabelon interactive elements - Using
Alert.alert()for complex choices (use bottom sheet instead) - Padding on
classNameof ScrollView (usecontentContainerClassName) - Inline anonymous functions in FlashList
renderItem(causes re-renders â extract component)