Agent skill
react-native
Best practices for React Native and Expo applications. Covers list performance, animations with Reanimated, navigation, UI patterns, and monorepo configuration. Use when building, reviewing, or optimizing React Native / Expo apps.
Install this agent skill to your Project
npx add-skill https://github.com/s-hiraoku/synapse-a2a/tree/main/.agents/skills/react-native
SKILL.md
React Native
Performance-first patterns for React Native and Expo, organized by impact.
Priority 1: List Performance (CRITICAL)
Lists are the #1 performance bottleneck in RN apps. Get these right first.
Use FlashList
Replace FlatList with @shopify/flash-list for large lists.
import { FlashList } from '@shopify/flash-list';
<FlashList
data={items}
renderItem={({ item }) => <ItemRow item={item} />}
estimatedItemSize={80}
keyExtractor={(item) => item.id}
/>
Memoize List Items
Every list item must be memoized.
const ItemRow = memo(function ItemRow({ item }: { item: Item }) {
return (
<View style={styles.row}>
<Text>{item.title}</Text>
</View>
);
});
Stabilize Callbacks
Extract callbacks and avoid inline objects in list items.
// BAD: New function + new style object every render
<Pressable onPress={() => onSelect(item.id)} style={{ padding: 16 }}>
// GOOD: Stable references
const handlePress = useCallback(() => onSelect(item.id), [item.id, onSelect]);
<Pressable onPress={handlePress} style={styles.pressable}>
Optimize Images in Lists
Use expo-image with proper sizing and caching.
import { Image } from 'expo-image';
<Image
source={{ uri: item.thumbnailUrl }}
style={styles.thumbnail}
contentFit="cover"
placeholder={item.blurhash}
transition={200}
recyclingKey={item.id}
/>
Item Types for Heterogeneous Lists
Use getItemType to help FlashList reuse cells efficiently.
<FlashList
data={mixedItems}
renderItem={renderItem}
getItemType={(item) => item.type} // 'header' | 'content' | 'ad'
estimatedItemSize={100}
/>
Priority 2: Animation (HIGH)
GPU-Only Properties
Only animate transform and opacity. Everything else triggers layout.
import Animated, { useAnimatedStyle, withSpring } from 'react-native-reanimated';
const animatedStyle = useAnimatedStyle(() => ({
transform: [{ scale: withSpring(isPressed.value ? 0.95 : 1) }],
opacity: withSpring(isVisible.value ? 1 : 0),
}));
Derived Values
Use useDerivedValue for computed animations to avoid redundant calculations.
const progress = useSharedValue(0);
const rotation = useDerivedValue(() => `${progress.value * 360}deg`);
const animatedStyle = useAnimatedStyle(() => ({
transform: [{ rotate: rotation.value }],
}));
Gesture Handling
Use react-native-gesture-handler for 60fps gesture tracking.
import { Gesture, GestureDetector } from 'react-native-gesture-handler';
const pan = Gesture.Pan()
.onUpdate((e) => {
translateX.value = e.translationX;
translateY.value = e.translationY;
})
.onEnd(() => {
translateX.value = withSpring(0);
translateY.value = withSpring(0);
});
// Use Gesture.Tap() instead of Pressable for animated press feedback
const tap = Gesture.Tap()
.onBegin(() => { scale.value = withSpring(0.95); })
.onFinalize(() => { scale.value = withSpring(1); });
Priority 3: Navigation (HIGH)
Native Navigators
Always prefer native stack and tabs over JS-based alternatives.
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
// BAD: JS-based stack (slower transitions, no native gestures)
import { createStackNavigator } from '@react-navigation/stack';
// GOOD: Native stack (native transitions + gestures)
const Stack = createNativeStackNavigator();
Screen Options
Configure headers and animations natively.
<Stack.Screen
name="Detail"
component={DetailScreen}
options={{
headerLargeTitle: true, // iOS large title
animation: 'slide_from_right',
}}
/>
Priority 4: UI Patterns (HIGH)
Safe Areas
Handle safe areas correctly for all device shapes.
import { SafeAreaView } from 'react-native-safe-area-context';
// For scrollable content
<SafeAreaView edges={['top']} style={{ flex: 1 }}>
<ScrollView contentInsetAdjustmentBehavior="automatic">
{children}
</ScrollView>
</SafeAreaView>
Native Modals
Use native modal presentation instead of JS overlays.
<Stack.Screen
name="Settings"
component={SettingsScreen}
options={{ presentation: 'modal' }}
/>
Native Menus
Use context menus instead of custom dropdown components.
import * as ContextMenu from 'zeego/context-menu';
<ContextMenu.Root>
<ContextMenu.Trigger>
<Pressable><Text>Options</Text></Pressable>
</ContextMenu.Trigger>
<ContextMenu.Content>
<ContextMenu.Item key="edit" onSelect={handleEdit}>
<ContextMenu.ItemTitle>Edit</ContextMenu.ItemTitle>
</ContextMenu.Item>
<ContextMenu.Item key="delete" onSelect={handleDelete} destructive>
<ContextMenu.ItemTitle>Delete</ContextMenu.ItemTitle>
</ContextMenu.Item>
</ContextMenu.Content>
</ContextMenu.Root>
Pressable Over TouchableOpacity
// BAD: Legacy touch component
<TouchableOpacity onPress={onPress}>{children}</TouchableOpacity>
// GOOD: Modern Pressable with feedback
<Pressable
onPress={onPress}
style={({ pressed }) => [styles.button, pressed && styles.pressed]}
android_ripple={{ color: 'rgba(0,0,0,0.1)' }}
>
{children}
</Pressable>
Priority 5: State Management (MEDIUM)
Minimize Re-renders
Subscribe only to the state you need.
// BAD: Re-renders on any store change
const store = useStore();
return <Text>{store.user.name}</Text>;
// GOOD: Selector extracts only needed value
const name = useStore((s) => s.user.name);
return <Text>{name}</Text>;
React Compiler Compatibility
When using React Compiler with Reanimated:
// Destructure shared value functions for compiler compatibility
const { value } = useSharedValue(0);
// Use worklet directive for Reanimated callbacks
const animatedStyle = useAnimatedStyle(() => {
'worklet';
return { opacity: value };
});
Priority 6: Monorepo (MEDIUM)
Native Dependencies
Keep native dependencies in the app package, not shared packages.
packages/
ui/ # Pure React components (no native deps)
shared/ # Business logic, types
apps/
mobile/ # Native deps (expo-image, reanimated) here
Single Dependency Versions
Enforce one version per dependency across the monorepo.
// Root package.json
{
"resolutions": {
"react-native": "0.76.x",
"react-native-reanimated": "3.x"
}
}
Quick Reference
| Issue | Fix | Priority |
|---|---|---|
| Slow scrolling lists | FlashList + memoized items | CRITICAL |
| Inline objects in lists | Extract to StyleSheet | CRITICAL |
| Janky animations | Only transform/opacity | HIGH |
| JS-based navigation | Native stack/tabs | HIGH |
| Custom dropdown menus | Native context menus | HIGH |
| Full store subscription | Selectors | MEDIUM |
| Native deps in shared pkg | Move to app package | MEDIUM |
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
task-planner
Guide for decomposing large tasks into a structured plan with dependency chains, managing priorities, and distributing work across agents. Outputs plan cards or delegation messages as the team contract; TodoList for personal micro-steps.
react-performance
Comprehensive React and Next.js performance optimization guide. Covers waterfall elimination, bundle size reduction, server-side optimization, re-render prevention, and rendering performance. Use when building, reviewing, or optimizing React/Next.js applications for speed.
release
Update version in pyproject.toml, plugin.json, and add changelog entry. This skill should be used when the user wants to bump the version number and update CHANGELOG.md. Triggered by /release or /version commands.
api-design
Guide API design for REST, GraphQL, gRPC, and CLI interfaces. Use this skill when designing new APIs, reviewing existing API contracts, or establishing API conventions for a project. Produces consistent, well-documented API specifications.
pr-guardian
Continuously monitor a GitHub PR for merge conflicts, CI failures, and CodeRabbit review comments, then automatically fix any issues found. Polls every 5 minutes and loops until every check is green. Use this skill whenever a PR has just been created or code has been pushed to a PR branch — it should be the default follow-up action after any PR creation or push. Also trigger on: "watch this PR", "guard this PR", "monitor CI", "keep fixing until green", "PRを監視して", "CIが通るまで 直して", /pr-guardian. When a PostToolUse hook reports that a push or PR creation just happened, proactively invoke this skill to start monitoring without waiting for the user to ask.
post-impl2
Workflow: Test workflow with non-existent agent target. . Triggered by /post-impl2 command.
Didn't find tool you were looking for?