‹ 首页

react-native

@jezweb · 收录于 1 周前 · 上游提交 2 周前

React Native and Expo patterns for building performant mobile apps. Covers list performance, animations with Reanimated, navigation, UI patterns, state management, platform-specific code, and Expo workflows. Use when building or reviewing React Native code. Triggers: 'react native', 'expo', 'mobile app', 'react native performance', 'flatlist', 'reanimated', 'expo router', 'mobile development', 'ios app', 'android app'.

适合你,如果正在用 React Native 或 Expo 开发移动应用

/ 下载安装
react-native.skill双击,或拖进 Claude 桌面版 / Cowork,即完成安装↓ .skill↓ .zip
用别的 agent?下载 .zip 解压,把文件夹放进它的技能目录
Claude Code~/.claude/skills/(项目级 .claude/skills/)
Codex CLI~/.codex/skills/
Cursor自动读取上面两处目录
其他工具见其文档的「skills」目录;两个下载是同一份文件,只是名字不同
/ 通过 npx 安装 校验哈希
npx oh-my-skill add jezweb/claude-skills/react-native
/ 通过 bash 安装
curl -fsSL https://oh-my-skill.com/install.sh | bash -s -- jezweb/claude-skills/react-native
/ 已经装过?验证本机副本,不用重装
npx oh-my-skill verify jezweb/claude-skills/react-native
安装目标可用 --agent / --scope 或 --to 明确指定;省略时只会在唯一已存在的 agent 目录上自动选择,零命中或多命中会停止并提示。content_hash 缺失或不一致均拒装。
910GitHub stars
~1.9K上下文体积 · 单文件
镜像托管

怎么用

技能原文 SKILL.md作者撰写 · MIT · e875a6b

React Native Patterns

Performance and architecture patterns for React Native + Expo apps. Rules ranked by impact — fix CRITICAL before touching MEDIUM.

This is a starting point. The skill will grow as you build more mobile apps.

When to Apply
  • Building new React Native or Expo apps
  • Optimising list and scroll performance
  • Implementing animations
  • Reviewing mobile code for performance issues
  • Setting up a new Expo project
1. List Performance (CRITICAL)

Lists are the #1 performance issue in React Native. A janky scroll kills the entire app experience.

| Pattern | Problem | Fix | |---------|---------|-----| | ScrollView for data | <ScrollView> renders all items at once | Use <FlatList> or <FlashList> — virtualised, only renders visible items | | Missing keyExtractor | FlatList without keyExtractor → unnecessary re-renders | keyExtractor={(item) => item.id} — stable unique key per item | | Complex renderItem | Expensive component in renderItem re-renders on every scroll | Wrap in React.memo, extract to separate component | | Inline functions in renderItem | renderItem={({ item }) => <Row onPress={() => nav(item.id)} />} | Extract handler: const handlePress = useCallback(...) | | No getItemLayout | FlatList measures every item on scroll (expensive) | Provide getItemLayout for fixed-height items: (data, index) => ({ length: 80, offset: 80 * index, index }) | | FlashList | FlatList is good, FlashList is better for large lists | @shopify/flash-list — drop-in replacement, recycling architecture | | Large images in lists | Full-res images decoded on main thread | Use expo-image with placeholder + transition, specify dimensions |

FlatList Checklist

Every FlatList should have:

<FlatList
  data={items}
  keyExtractor={(item) => item.id}
  renderItem={renderItem}           // Memoised component
  getItemLayout={getItemLayout}     // If items are fixed height
  initialNumToRender={10}           // Don't render 100 items on mount
  maxToRenderPerBatch={10}          // Batch size for off-screen rendering
  windowSize={5}                    // How many screens to keep in memory
  removeClippedSubviews={true}      // Unmount off-screen items (Android)
/>
2. Animations (HIGH)

Native animations run on the UI thread. JS animations block the JS thread and cause jank.

| Pattern | Problem | Fix | |---------|---------|-----| | Animated API for complex animations | Animated runs on JS thread, blocks interactions | Use react-native-reanimated — runs on UI thread | | Layout animation | Item appears/disappears with no transition | LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut) | | Shared element transitions | Navigate between screens, element teleports | react-native-reanimated shared transitions or expo-router shared elements | | Gesture + animation | Drag/swipe feels laggy | react-native-gesture-handler + reanimated worklets — all on UI thread | | Measuring layout | onLayout fires too late, causes flash | Use useAnimatedStyle with shared values for instant response |

Reanimated Basics
import Animated, { useSharedValue, useAnimatedStyle, withSpring } from 'react-native-reanimated';

function AnimatedBox() {
  const offset = useSharedValue(0);
  const style = useAnimatedStyle(() => ({
    transform: [{ translateX: withSpring(offset.value) }],
  }));

  return (
    <GestureDetector gesture={panGesture}>
      <Animated.View style={[styles.box, style]} />
    </GestureDetector>
  );
}
3. Navigation (HIGH)

| Pattern | Problem | Fix | |---------|---------|-----| | Expo Router | File-based routing (like Next.js) for React Native | app/ directory with _layout.tsx files. Preferred for new Expo projects. | | Heavy screens on stack | Every screen stays mounted in the stack | Use unmountOnBlur: true for screens that don't need to persist | | Deep linking | App doesn't respond to URLs | Expo Router handles this automatically. For bare RN: Linking API config | | Tab badge updates | Badge count doesn't update when tab is focused | Use useIsFocused() or refetch on focus: useFocusEffect(useCallback(...)) | | Navigation state persistence | App loses position on background/kill | onStateChange + initialState with AsyncStorage |

Expo Router Structure
app/
├── _layout.tsx          # Root layout (tab navigator)
├── index.tsx            # Home tab
├── (tabs)/
│   ├── _layout.tsx      # Tab bar config
│   ├── home.tsx
│   ├── search.tsx
│   └── profile.tsx
├── [id].tsx             # Dynamic route
└── modal.tsx            # Modal route
4. UI Patterns (HIGH)

| Pattern | Problem | Fix | |---------|---------|-----| | Safe area | Content under notch or home indicator | <SafeAreaView> or useSafeAreaInsets() from react-native-safe-area-context | | Keyboard avoidance | Form fields hidden behind keyboard | <KeyboardAvoidingView behavior={Platform.OS === 'ios' ? 'padding' : 'height'}> | | Platform-specific code | iOS and Android need different behaviour | Platform.select({ ios: ..., android: ... }) or .ios.tsx / .android.tsx files | | Status bar | Status bar overlaps content or wrong colour | <StatusBar style="auto" /> from expo-status-bar in root layout | | Touch targets | Buttons too small to tap | Minimum 44x44pt. Use hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }} | | Haptic feedback | Taps feel dead | expo-hapticsHaptics.impactAsync(Haptics.ImpactFeedbackStyle.Light) on important actions |

5. Images and Media (MEDIUM)

| Pattern | Problem | Fix | |---------|---------|-----| | Image component | <Image> from react-native is basic | Use expo-image — caching, placeholder, transition, blurhash | | Remote images without dimensions | Layout shift when image loads | Always specify width and height, or use aspectRatio | | Large images | OOM crashes on Android | Resize server-side or use expo-image which handles memory | | SVG | SVG support isn't native | react-native-svg + react-native-svg-transformer for SVG imports | | Video | Video playback | expo-av or expo-video (newer API) |

6. State and Data (MEDIUM)

| Pattern | Problem | Fix | |---------|---------|-----| | AsyncStorage for complex data | JSON parse/stringify on every read | Use MMKV (react-native-mmkv) — 30x faster than AsyncStorage | | Global state | Redux/MobX boilerplate for simple state | Zustand — minimal, works great with React Native | | Server state | Manual fetch + loading + error + cache | TanStack Query — same as web, works in React Native | | Offline first | App unusable without network | TanStack Query persistQueryClient + MMKV, or WatermelonDB for complex offline | | Deep state updates | Spread operator hell for nested objects | Immer via Zustand: set(produce(state => { state.user.name = 'new' })) |

7. Expo Workflow (MEDIUM)

| Pattern | When | How | |---------|------|-----| | Development build | Need native modules | npx expo run:ios or eas build --profile development | | Expo Go | Quick prototyping, no native modules | npx expo start — scan QR code | | EAS Build | CI/CD, app store builds | eas build --platform ios --profile production | | EAS Update | Hot fix without app store review | eas update --branch production --message "Fix bug" | | Config plugins | Modify native config without ejecting | app.config.ts with expo-build-properties or custom config plugin | | Environment variables | Different configs per build | eas.json build profiles + expo-constants |

New Project Setup
npx create-expo-app my-app --template tabs
cd my-app
npx expo install expo-image react-native-reanimated react-native-gesture-handler react-native-safe-area-context
8. Testing (LOW-MEDIUM)

| Tool | For | Setup | |------|-----|-------| | Jest | Unit tests, hook tests | Included with Expo by default | | React Native Testing Library | Component tests | @testing-library/react-native | | Detox | E2E tests on real devices/simulators | detox — Wix's testing framework | | Maestro | E2E with YAML flows | maestro test flow.yaml — simpler than Detox |

Common Gotchas

| Gotcha | Fix | |--------|-----| | Metro bundler cache | npx expo start --clear | | Pod install issues (iOS) | cd ios && pod install --repo-update | | Reanimated not working | Must be first import: import 'react-native-reanimated' in root | | Expo SDK upgrade | npx expo install --fix after updating SDK version | | Android build fails | Check gradle.properties for memory: org.gradle.jvmargs=-Xmx4g | | iOS simulator slow | Use physical device for performance testing — simulator doesn't reflect real perf |

按 MIT 许可原样转载,未经改动 · 在 GitHub 查看 →

评论

登录即可评论;带「已验证安装」的,是发布者名下有本店的安装或持有记录。