react-native-expert
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseReact Native Expert Skill
React Native专家技能
Expert-level React Native patterns, mobile-specific optimizations, navigation, and platform handling.
专家级React Native模式、移动端特定优化、导航和平台适配方案。
Auto-Detection
自动触发场景
This skill activates when:
- Working with React Native projects
- Detected or
react-nativein package.jsonexpo - Building mobile components
- Platform-specific code needed
当以下情况时,该技能会激活:
- 处理React Native项目时
- 在package.json中检测到或
react-native时expo - 构建移动端组件时
- 需要平台特定代码时
1. Project Structure
1. 项目结构
Recommended Structure
推荐的项目结构
src/
├── components/ # Shared components
│ ├── ui/ # Base UI components
│ └── common/ # Business components
├── screens/ # Screen components
├── navigation/ # Navigation config
├── hooks/ # Custom hooks
├── services/ # API services
├── stores/ # State management
├── utils/ # Utilities
├── constants/ # App constants
├── types/ # TypeScript types
└── assets/ # Images, fontssrc/
├── components/ # 通用组件
│ ├── ui/ # 基础UI组件
│ └── common/ # 业务组件
├── screens/ # 页面组件
├── navigation/ # 导航配置
├── hooks/ # 自定义hooks
├── services/ # API服务
├── stores/ # 状态管理
├── utils/ # 工具函数
├── constants/ # 应用常量
├── types/ # TypeScript类型定义
└── assets/ # 图片、字体等资源2. Component Patterns
2. 组件模式
Adaptive Styling Detection
自适应样式检测
typescript
// ✅ GOOD - Detect and use project's styling approach
// Check package.json for: nativewind, emotion, styled-components, or use StyleSheet
// NativeWind (Tailwind)
import { styled } from 'nativewind';
const StyledView = styled(View);
<StyledView className="flex-1 bg-white p-4" />
// StyleSheet (default)
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: 'white', padding: 16 },
});
<View style={styles.container} />
// Emotion
import styled from '@emotion/native';
const Container = styled.View`flex: 1; background-color: white;`;typescript
// ✅ 推荐 - 检测并适配项目的样式方案
// 检查package.json中是否包含:nativewind、emotion、styled-components,或使用StyleSheet
// NativeWind(Tailwind风格)
import { styled } from 'nativewind';
const StyledView = styled(View);
<StyledView className="flex-1 bg-white p-4" />
// StyleSheet(默认方案)
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: 'white', padding: 16 },
});
<View style={styles.container} />
// Emotion
import styled from '@emotion/native';
const Container = styled.View`flex: 1; background-color: white;`;Performance-Optimized Components
性能优化组件
tsx
// ✅ GOOD - Memoized list item
const ListItem = React.memo(function ListItem({ item, onPress }: Props) {
const handlePress = useCallback(() => {
onPress(item.id);
}, [item.id, onPress]);
return (
<Pressable onPress={handlePress}>
<Text>{item.title}</Text>
</Pressable>
);
});
// ✅ GOOD - Pressable over TouchableOpacity
<Pressable
onPress={handlePress}
style={({ pressed }) => [
styles.button,
pressed && styles.buttonPressed
]}
android_ripple={{ color: 'rgba(0,0,0,0.1)' }}
>
<Text>Press Me</Text>
</Pressable>tsx
// ✅ 推荐 - 记忆化列表项组件
const ListItem = React.memo(function ListItem({ item, onPress }: Props) {
const handlePress = useCallback(() => {
onPress(item.id);
}, [item.id, onPress]);
return (
<Pressable onPress={handlePress}>
<Text>{item.title}</Text>
</Pressable>
);
});
// ✅ 推荐 - 使用Pressable替代TouchableOpacity
<Pressable
onPress={handlePress}
style={({ pressed }) => [
styles.button,
pressed && styles.buttonPressed
]}
android_ripple={{ color: 'rgba(0,0,0,0.1)' }}
>
<Text>Press Me</Text>
</Pressable>3. FlatList Optimization
3. FlatList优化
Required Optimizations
必备优化项
tsx
// ✅ GOOD - Optimized FlatList
<FlatList
data={items}
renderItem={renderItem}
keyExtractor={keyExtractor}
// Performance props
removeClippedSubviews={true}
maxToRenderPerBatch={10}
windowSize={5}
initialNumToRender={10}
getItemLayout={getItemLayout} // If fixed height
// Memoized functions
ListEmptyComponent={EmptyComponent}
ListHeaderComponent={HeaderComponent}
ListFooterComponent={FooterComponent}
// Prevent re-renders
extraData={selectedId}
/>
// ✅ GOOD - Memoized renderItem
const renderItem = useCallback(({ item }: { item: Item }) => (
<ListItem item={item} onPress={handlePress} />
), [handlePress]);
// ✅ GOOD - Stable keyExtractor
const keyExtractor = useCallback((item: Item) => item.id, []);
// ✅ GOOD - getItemLayout for fixed height items
const getItemLayout = useCallback((
_data: Item[] | null | undefined,
index: number
) => ({
length: ITEM_HEIGHT,
offset: ITEM_HEIGHT * index,
index,
}), []);tsx
// ✅ 推荐 - 优化后的FlatList
<FlatList
data={items}
renderItem={renderItem}
keyExtractor={keyExtractor}
// 性能相关属性
removeClippedSubviews={true}
maxToRenderPerBatch={10}
windowSize={5}
initialNumToRender={10}
getItemLayout={getItemLayout} // 固定高度时使用
// 记忆化函数
ListEmptyComponent={EmptyComponent}
ListHeaderComponent={HeaderComponent}
ListFooterComponent={FooterComponent}
// 防止不必要重渲染
extraData={selectedId}
/>
// ✅ 推荐 - 记忆化renderItem函数
const renderItem = useCallback(({ item }: { item: Item }) => (
<ListItem item={item} onPress={handlePress} />
), [handlePress]);
// ✅ 推荐 - 稳定的keyExtractor函数
const keyExtractor = useCallback((item: Item) => item.id, []);
// ✅ 推荐 - 固定高度列表使用getItemLayout
const getItemLayout = useCallback((
_data: Item[] | null | undefined,
index: number
) => ({
length: ITEM_HEIGHT,
offset: ITEM_HEIGHT * index,
index,
}), []);FlashList Alternative
FlashList替代方案
tsx
// ✅ BETTER - Use FlashList for large lists
import { FlashList } from '@shopify/flash-list';
<FlashList
data={items}
renderItem={renderItem}
estimatedItemSize={ITEM_HEIGHT}
keyExtractor={keyExtractor}
/>tsx
// ✅ 更优 - 大数据列表使用FlashList
import { FlashList } from '@shopify/flash-list';
<FlashList
data={items}
renderItem={renderItem}
estimatedItemSize={ITEM_HEIGHT}
keyExtractor={keyExtractor}
/>4. Navigation (React Navigation)
4. 导航(React Navigation)
Type-Safe Navigation
类型安全导航
tsx
// ✅ GOOD - Define navigation types
type RootStackParamList = {
Home: undefined;
Profile: { userId: string };
Settings: { section?: string };
};
type ProfileScreenProps = NativeStackScreenProps<RootStackParamList, 'Profile'>;
// ✅ GOOD - Type-safe navigation hook
import { useNavigation } from '@react-navigation/native';
import type { NativeStackNavigationProp } from '@react-navigation/native-stack';
type NavigationProp = NativeStackNavigationProp<RootStackParamList>;
function MyComponent() {
const navigation = useNavigation<NavigationProp>();
const goToProfile = (userId: string) => {
navigation.navigate('Profile', { userId });
};
}tsx
// ✅ 推荐 - 定义导航类型
type RootStackParamList = {
Home: undefined;
Profile: { userId: string };
Settings: { section?: string };
};
type ProfileScreenProps = NativeStackScreenProps<RootStackParamList, 'Profile'>;
// ✅ 推荐 - 类型安全的导航Hook
import { useNavigation } from '@react-navigation/native';
import type { NativeStackNavigationProp } from '@react-navigation/native-stack';
type NavigationProp = NativeStackNavigationProp<RootStackParamList>;
function MyComponent() {
const navigation = useNavigation<NavigationProp>();
const goToProfile = (userId: string) => {
navigation.navigate('Profile', { userId });
};
}Deep Linking
深度链接
tsx
// ✅ GOOD - Configure deep linking
const linking = {
prefixes: ['myapp://', 'https://myapp.com'],
config: {
screens: {
Home: '',
Profile: 'user/:userId',
Settings: 'settings',
},
},
};
<NavigationContainer linking={linking}>
{/* ... */}
</NavigationContainer>tsx
// ✅ 推荐 - 配置深度链接
const linking = {
prefixes: ['myapp://', 'https://myapp.com'],
config: {
screens: {
Home: '',
Profile: 'user/:userId',
Settings: 'settings',
},
},
};
<NavigationContainer linking={linking}>
{/* ... */}
</NavigationContainer>5. Platform-Specific Code
5. 平台特定代码
Platform Selection
平台选择
tsx
import { Platform, StyleSheet } from 'react-native';
// ✅ GOOD - Platform.select
const styles = StyleSheet.create({
shadow: Platform.select({
ios: {
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.25,
shadowRadius: 3.84,
},
android: {
elevation: 5,
},
default: {},
}),
});
// ✅ GOOD - Platform-specific files
// Button.ios.tsx
// Button.android.tsx
// Button.tsx (fallback)
import Button from './Button'; // Auto-selects platformtsx
import { Platform, StyleSheet } from 'react-native';
// ✅ 推荐 - 使用Platform.select
const styles = StyleSheet.create({
shadow: Platform.select({
ios: {
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.25,
shadowRadius: 3.84,
},
android: {
elevation: 5,
},
default: {},
}),
});
// ✅ 推荐 - 平台特定文件
// Button.ios.tsx
// Button.android.tsx
// Button.tsx( fallback )
import Button from './Button'; // 自动适配平台Safe Area Handling
安全区域适配
tsx
import { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context';
// ✅ GOOD - SafeAreaView for screens
function Screen() {
return (
<SafeAreaView style={{ flex: 1 }} edges={['top', 'bottom']}>
<Content />
</SafeAreaView>
);
}
// ✅ GOOD - useSafeAreaInsets for custom handling
function CustomHeader() {
const insets = useSafeAreaInsets();
return (
<View style={{ paddingTop: insets.top }}>
<HeaderContent />
</View>
);
}tsx
import { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context';
// ✅ 推荐 - 页面使用SafeAreaView
function Screen() {
return (
<SafeAreaView style={{ flex: 1 }} edges={['top', 'bottom']}>
<Content />
</SafeAreaView>
);
}
// ✅ 推荐 - 自定义场景使用useSafeAreaInsets
function CustomHeader() {
const insets = useSafeAreaInsets();
return (
<View style={{ paddingTop: insets.top }}>
<HeaderContent />
</View>
);
}6. Image Handling
6. 图片处理
Optimized Images
优化的图片处理方案
tsx
import FastImage from 'react-native-fast-image';
// ✅ GOOD - Use FastImage for network images
<FastImage
source={{
uri: imageUrl,
priority: FastImage.priority.normal,
cache: FastImage.cacheControl.immutable,
}}
style={styles.image}
resizeMode={FastImage.resizeMode.cover}
/>
// ✅ GOOD - Preload images
FastImage.preload([
{ uri: 'https://example.com/image1.jpg' },
{ uri: 'https://example.com/image2.jpg' },
]);
// ✅ GOOD - Local images with require
<Image source={require('./assets/logo.png')} />tsx
import FastImage from 'react-native-fast-image';
// ✅ 推荐 - 网络图片使用FastImage
<FastImage
source={{
uri: imageUrl,
priority: FastImage.priority.normal,
cache: FastImage.cacheControl.immutable,
}}
style={styles.image}
resizeMode={FastImage.resizeMode.cover}
/>
// ✅ 推荐 - 预加载图片
FastImage.preload([
{ uri: 'https://example.com/image1.jpg' },
{ uri: 'https://example.com/image2.jpg' },
]);
// ✅ 推荐 - 本地图片使用require
<Image source={require('./assets/logo.png')} />7. Animations
7. 动画
Reanimated Best Practices
Reanimated最佳实践
tsx
import Animated, {
useSharedValue,
useAnimatedStyle,
withSpring,
withTiming,
runOnJS,
} from 'react-native-reanimated';
// ✅ GOOD - Worklet-based animations
function AnimatedCard() {
const scale = useSharedValue(1);
const animatedStyle = useAnimatedStyle(() => ({
transform: [{ scale: scale.value }],
}));
const handlePressIn = () => {
scale.value = withSpring(0.95);
};
const handlePressOut = () => {
scale.value = withSpring(1);
};
return (
<Pressable onPressIn={handlePressIn} onPressOut={handlePressOut}>
<Animated.View style={[styles.card, animatedStyle]}>
<Content />
</Animated.View>
</Pressable>
);
}tsx
import Animated, {
useSharedValue,
useAnimatedStyle,
withSpring,
withTiming,
runOnJS,
} from 'react-native-reanimated';
// ✅ 推荐 - 基于Worklet的动画
function AnimatedCard() {
const scale = useSharedValue(1);
const animatedStyle = useAnimatedStyle(() => ({
transform: [{ scale: scale.value }],
}));
const handlePressIn = () => {
scale.value = withSpring(0.95);
};
const handlePressOut = () => {
scale.value = withSpring(1);
};
return (
<Pressable onPressIn={handlePressIn} onPressOut={handlePressOut}>
<Animated.View style={[styles.card, animatedStyle]}>
<Content />
</Animated.View>
</Pressable>
);
}Gesture Handler
手势处理
tsx
import { Gesture, GestureDetector } from 'react-native-gesture-handler';
// ✅ GOOD - Gesture-based interactions
function SwipeableCard() {
const translateX = useSharedValue(0);
const gesture = Gesture.Pan()
.onUpdate((e) => {
translateX.value = e.translationX;
})
.onEnd(() => {
translateX.value = withSpring(0);
});
const animatedStyle = useAnimatedStyle(() => ({
transform: [{ translateX: translateX.value }],
}));
return (
<GestureDetector gesture={gesture}>
<Animated.View style={animatedStyle}>
<Card />
</Animated.View>
</GestureDetector>
);
}tsx
import { Gesture, GestureDetector } from 'react-native-gesture-handler';
// ✅ 推荐 - 基于手势的交互
function SwipeableCard() {
const translateX = useSharedValue(0);
const gesture = Gesture.Pan()
.onUpdate((e) => {
translateX.value = e.translationX;
})
.onEnd(() => {
translateX.value = withSpring(0);
});
const animatedStyle = useAnimatedStyle(() => ({
transform: [{ translateX: translateX.value }],
}));
return (
<GestureDetector gesture={gesture}>
<Animated.View style={animatedStyle}>
<Card />
</Animated.View>
</GestureDetector>
);
}8. Storage & Persistence
8. 存储与持久化
tsx
import AsyncStorage from '@react-native-async-storage/async-storage';
import * as SecureStore from 'expo-secure-store';
// ✅ GOOD - AsyncStorage for non-sensitive data
async function saveSettings(settings: Settings) {
await AsyncStorage.setItem('settings', JSON.stringify(settings));
}
// ✅ GOOD - SecureStore for sensitive data
async function saveToken(token: string) {
await SecureStore.setItemAsync('authToken', token);
}
// ✅ GOOD - MMKV for performance-critical storage
import { MMKV } from 'react-native-mmkv';
const storage = new MMKV();
storage.set('user.name', 'John');
const name = storage.getString('user.name');tsx
import AsyncStorage from '@react-native-async-storage/async-storage';
import * as SecureStore from 'expo-secure-store';
// ✅ 推荐 - 非敏感数据使用AsyncStorage
async function saveSettings(settings: Settings) {
await AsyncStorage.setItem('settings', JSON.stringify(settings));
}
// ✅ 推荐 - 敏感数据使用SecureStore
async function saveToken(token: string) {
await SecureStore.setItemAsync('authToken', token);
}
// ✅ 推荐 - 性能敏感场景使用MMKV
import { MMKV } from 'react-native-mmkv';
const storage = new MMKV();
storage.set('user.name', 'John');
const name = storage.getString('user.name');9. Testing
9. 测试
tsx
import { render, fireEvent, waitFor } from '@testing-library/react-native';
// ✅ GOOD - Component testing
describe('LoginButton', () => {
it('calls onPress when pressed', () => {
const onPress = jest.fn();
const { getByText } = render(<LoginButton onPress={onPress} />);
fireEvent.press(getByText('Login'));
expect(onPress).toHaveBeenCalled();
});
});
// ✅ GOOD - Async testing
it('shows loading then content', async () => {
const { getByTestId, queryByTestId } = render(<DataScreen />);
expect(getByTestId('loading')).toBeTruthy();
await waitFor(() => {
expect(queryByTestId('loading')).toBeNull();
expect(getByTestId('content')).toBeTruthy();
});
});tsx
import { render, fireEvent, waitFor } from '@testing-library/react-native';
// ✅ 推荐 - 组件测试
describe('LoginButton', () => {
it('点击时触发onPress', () => {
const onPress = jest.fn();
const { getByText } = render(<LoginButton onPress={onPress} />);
fireEvent.press(getByText('Login'));
expect(onPress).toHaveBeenCalled();
});
});
// ✅ 推荐 - 异步测试
it('先显示加载状态再显示内容', async () => {
const { getByTestId, queryByTestId } = render(<DataScreen />);
expect(getByTestId('loading')).toBeTruthy();
await waitFor(() => {
expect(queryByTestId('loading')).toBeNull();
expect(getByTestId('content')).toBeTruthy();
});
});Quick Reference
快速参考
toon
checklist[12]{area,best_practice}:
Lists,Use FlashList or optimized FlatList
Images,Use FastImage for network images
Navigation,Type-safe with RootStackParamList
Styling,Detect project approach (NativeWind/StyleSheet)
Platform,Use Platform.select for differences
Safe area,Use SafeAreaView or useSafeAreaInsets
Animations,Use Reanimated for 60fps
Gestures,Use Gesture Handler
Storage,SecureStore for tokens AsyncStorage for prefs
Performance,Memoize components and callbacks
Testing,React Native Testing Library
Pressable,Use over TouchableOpacityVersion: 1.3.0
toon
checklist[12]{area,best_practice}:
Lists,Use FlashList or optimized FlatList
Images,Use FastImage for network images
Navigation,Type-safe with RootStackParamList
Styling,Detect project approach (NativeWind/StyleSheet)
Platform,Use Platform.select for differences
Safe area,Use SafeAreaView or useSafeAreaInsets
Animations,Use Reanimated for 60fps
Gestures,Use Gesture Handler
Storage,SecureStore for tokens AsyncStorage for prefs
Performance,Memoize components and callbacks
Testing,React Native Testing Library
Pressable,Use over TouchableOpacity版本: 1.3.0