React native
Skill nimadorostkar/Claude-Skills-collection/skills/mobile/react-native
Use when building cross-platform mobile apps with React Native or Expo. Covers navigation, platform differences, list performance, native modules, offline behavior, and release builds.From its SKILL.md
npx -y skills add nimadorostkar/Claude-Skills-collection --skill react-nativeAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
SKILL.md
4.9 KB, ~1.0k tokens by cl100k_base, as published. Nobody here has run it
React Native
Purpose
Build React Native applications that feel native: lists that scroll at 60fps, navigation that matches platform conventions, and a release pipeline that does not surprise you at submission.
When to Use
- Building or reviewing a React Native or Expo application.
- Diagnosing list performance or dropped frames.
- Bridging to a native module.
- Setting up over-the-air updates and release builds.
Capabilities
- Navigation with React Navigation or Expo Router, including deep links.
- Platform-specific behavior and styling.
- List performance:
FlashList, virtualization, memoized rows. - Native modules and the new architecture (Fabric, TurboModules).
- Offline support, secure storage, and background tasks.
- Release: EAS Build, OTA updates, store submission.
Inputs
- The feature set, target platforms, and minimum OS versions.
- Whether native modules are needed (this determines Expo Go versus a dev build).
- Performance requirements, especially for lists and animation.
Outputs
- A navigation structure with deep-link support.
- Lists that maintain frame rate with realistic data volumes.
- A build and release pipeline for both platforms.
Workflow
- Choose the runtime honestly — Expo with a development build gives you native modules and the Expo tooling. Expo Go is for prototypes; bare React Native is for teams that need full native control and are prepared to maintain it.
- Structure navigation first — Stacks inside tabs, with a typed route map. Retrofitting deep links into an untyped navigator is painful.
- Fix lists before they are slow —
FlashListwith a stablekeyExtractor, memoized row components, and a fixed item size where possible.ScrollViewwith a hundred children will drop frames on a mid-range Android. - Handle platform differences explicitly —
Platform.selectfor behavior, not just style. Back-button behavior, safe areas, and permission flows differ genuinely. - Move animation off the JS thread — Reanimated worklets run on the UI thread. Animating via
setStatewill jank the moment the JS thread does anything else. - Test the release build — Debug builds hide performance problems entirely. Profile in release, on a real mid-range device.
Best Practices
- The JS thread and the UI thread are separate. Any heavy JavaScript blocks interaction, and it will not show up in a simulator on a fast laptop.
- An inline arrow function as a
renderItemre-creates every row on every render. Memoize the row component and hoist the callback. useNativeDriver: trueon everyAnimatedusage, or use Reanimated. Without it, every frame crosses the bridge.- Store tokens in
expo-secure-storeor Keychain — neverAsyncStorage, which is unencrypted plain text. - Images are the main cause of memory pressure. Size them to the display size; do not load a 4000px original into a 100px thumbnail.
- OTA updates cannot change native code. If you added a native module, the update requires a store release.
Examples
A list that stays at 60fps:
const OrderRow = memo(function OrderRow({ order, onPress }: OrderRowProps) {
return (
<Pressable onPress={() => onPress(order.id)} style={styles.row}>
<Text style={styles.title}>{order.reference}</Text>
<Text style={styles.meta}>{order.customerName}</Text>
</Pressable>
);
});
export function OrderList({ orders }: { orders: Order[] }) {
const router = useRouter();
const onPress = useCallback((id: string) => router.push(`/orders/${id}`), [router]);
return (
<FlashList
data={orders}
renderItem={({ item }) => <OrderRow order={item} onPress={onPress} />}
keyExtractor={(item) => item.id}
estimatedItemSize={72} // FlashList needs this to recycle correctly
removeClippedSubviews
/>
);
}
onPress is hoisted and stable, OrderRow is memoized, so scrolling re-renders nothing that has not changed.
Animation on the UI thread:
const offset = useSharedValue(0);
const style = useAnimatedStyle(() => ({
transform: [{ translateY: withSpring(offset.value) }],
}));
// Runs on the UI thread — unaffected by whatever the JS thread is doing.
Notes
- The new architecture (Fabric + TurboModules) removes the asynchronous bridge and is the default from React Native 0.76. Older third-party native modules may not be compatible — check before upgrading.
estimatedItemSizeonFlashListis not optional in practice; a bad estimate causes visible blank space during fast scrolls.- Hermes is the default engine and materially improves startup time and memory. If a project is still on JSC, that is usually an oversight.
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.