React Native 学习指南
# React Native 学习指南
# 📚 目录导航
- 1️⃣ 快速开始
- 2️⃣ 核心概念
- 3️⃣ 组件系统
- 4️⃣ 样式与布局
- 5️⃣ 核心 API
- 6️⃣ 导航与路由
- 7️⃣ 状态管理
- 8️⃣ 网络与数据
- 9️⃣ 原生模块
- 🔟 调试与优化
- 1️⃣1️⃣ 实战项目
- 1️⃣2️⃣ 常见问题
# 1️⃣ 快速开始
# React Native 简介
React Native 是 Facebook 推出的跨平台移动应用开发框架,使用 JavaScript 和 React 构建原生移动应用。
核心特性:
- ✅ 跨平台:一套代码同时支持 iOS 和 Android
- ✅ 原生性能:渲染真实的原生组件,而非 WebView
- ✅ 热更新:支持 Fast Refresh,快速迭代开发
- ✅ React 生态:使用熟悉的 React 语法和生态系统
- ✅ 原生能力:可直接调用原生 API 和模块
# 环境搭建
# 安装依赖
# 安装 Node.js (建议 LTS 版本)
# 访问 https://nodejs.org/
# 安装 Watchman (macOS)
brew install watchman
# 安装 React Native CLI
npm install -g react-native-cli
# 或使用 npx (推荐)
npx react-native@latest
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# iOS 开发环境 (macOS)
# 安装 Xcode (App Store)
# 安装 CocoaPods
sudo gem install cocoapods
# 验证安装
pod --version
1
2
3
4
5
6
2
3
4
5
6
# Android 开发环境
# 1. 下载安装 Android Studio
# https://developer.android.com/studio
# 2. 配置环境变量 (~/.zshrc 或 ~/.bash_profile)
export ANDROID_HOME=$HOME/Library/Android/sdk
export PATH=$PATH:$ANDROID_HOME/emulator
export PATH=$PATH:$ANDROID_HOME/tools
export PATH=$PATH:$ANDROID_HOME/tools/bin
export PATH=$PATH:$ANDROID_HOME/platform-tools
# 3. 重新加载配置
source ~/.zshrc
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# 创建第一个项目
# 使用 React Native CLI
npx react-native@latest init MyApp
# 或使用 Expo (更简单,推荐新手)
npx create-expo-app MyApp
cd MyApp
# 启动项目
npm start
# 或
npx expo start
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# 运行应用
# iOS
npx react-native run-ios
# 指定设备
npx react-native run-ios --simulator="iPhone 15 Pro"
# Android
npx react-native run-android
# Expo
npx expo run:ios
npx expo run:android
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# Hello World 示例
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
export default function App() {
return (
<View style={styles.container}>
<Text style={styles.text}>Hello, React Native! 🎉</Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#f5f5f5',
},
text: {
fontSize: 24,
fontWeight: 'bold',
color: '#333',
},
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 2️⃣ 核心概念
# 架构原理
React Native 使用三层架构:
graph TB
A[JavaScript 层] -->|通过 Bridge| B[C++ Bridge]
B -->|调用| C[原生层 Native]
C -->|回调| B
B -->|返回| A
A1[React 组件] --> A
A2[业务逻辑] --> A
C1[iOS UIKit] --> C
C2[Android Views] --> C
新架构(Fabric + TurboModules):
graph LR
A[JavaScript] -->|JSI 直接调用| B[C++ Native]
B -->|同步返回| A
style A fill:#61dafb
style B fill:#90ee90
# 核心概念解析
# 1. Bridge 通信机制
旧架构 Bridge:
// JavaScript 调用原生模块
import { NativeModules } from 'react-native';
const { CalendarModule } = NativeModules;
// 异步调用
CalendarModule.createCalendarEvent('Party', 'My House')
.then(eventId => console.log(`Created event ${eventId}`));
1
2
3
4
5
6
7
2
3
4
5
6
7
工作流程:
JavaScript Bridge Native
| | |
|------ 序列化 JSON ---->| |
| |---- 异步调用 ----->|
| | | 处理
| |<--- 返回结果 -----|
|<----- 解析 JSON ------| |
1
2
3
4
5
6
7
2
3
4
5
6
7
# 2. 组件生命周期
class MyComponent extends React.Component {
// 1. 构造函数
constructor(props) {
super(props);
this.state = { count: 0 };
}
// 2. 挂载前
componentDidMount() {
console.log('Component mounted');
}
// 3. 更新时
componentDidUpdate(prevProps, prevState) {
console.log('Component updated');
}
// 4. 卸载前
componentWillUnmount() {
console.log('Component will unmount');
}
render() {
return <Text>{this.state.count}</Text>;
}
}
// Hooks 写法(推荐)
function MyComponent() {
const [count, setCount] = useState(0);
useEffect(() => {
console.log('Component mounted');
return () => console.log('Component will unmount');
}, []);
useEffect(() => {
console.log('Count updated:', count);
}, [count]);
return <Text>{count}</Text>;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# 3. Yoga 布局引擎
React Native 使用 Yoga (opens new window) 进行布局,基于 Flexbox 实现。
<View style={{
flex: 1, // 占据父容器剩余空间
flexDirection: 'row', // 主轴方向:row | column
justifyContent: 'center', // 主轴对齐
alignItems: 'center', // 交叉轴对齐
}}>
<View style={{ width: 50, height: 50 }} />
</View>
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
Yoga 特点:
- ✅ 高性能的 C++ 布局引擎
- ✅ 支持 Flexbox 布局
- ✅ 跨平台一致性
- ✅ 自动计算布局
# 4. 渲染流程
sequenceDiagram
participant JS as JavaScript
participant Shadow as Shadow Tree
participant Native as Native UI
JS->>Shadow: 1. 创建虚拟 DOM
Shadow->>Shadow: 2. 计算布局 (Yoga)
Shadow->>Native: 3. 生成原生视图
Native->>Native: 4. 渲染到屏幕
# 3️⃣ 组件系统
# 基础组件
# View - 容器组件
import { View } from 'react-native';
<View style={{
backgroundColor: '#fff',
padding: 20,
borderRadius: 10,
}}>
{/* 子组件 */}
</View>
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# Text - 文本组件
import { Text } from 'react-native';
<Text
style={{ fontSize: 16, color: '#333' }}
numberOfLines={2} // 最多显示 2 行
ellipsizeMode="tail" // 省略号位置
onPress={() => console.log('Pressed')}
>
Hello World
</Text>
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# Image - 图片组件
import { Image } from 'react-native';
// 本地图片
<Image
source={require('./assets/logo.png')}
style={{ width: 100, height: 100 }}
resizeMode="cover" // cover | contain | stretch | repeat | center
/>
// 网络图片
<Image
source={{ uri: 'https://example.com/image.png' }}
style={{ width: 100, height: 100 }}
/>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
# ScrollView - 滚动容器
import { ScrollView } from 'react-native';
<ScrollView
horizontal={false} // 水平滚动
showsVerticalScrollIndicator={true}
onScroll={(e) => console.log(e.nativeEvent.contentOffset.y)}
scrollEventThrottle={16} // 滚动事件触发频率
>
{/* 内容 */}
</ScrollView>
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# FlatList - 高性能列表
import { FlatList } from 'react-native';
const DATA = [
{ id: '1', title: 'Item 1' },
{ id: '2', title: 'Item 2' },
];
<FlatList
data={DATA}
keyExtractor={(item) => item.id}
renderItem={({ item }) => (
<Text>{item.title}</Text>
)}
// 性能优化
initialNumToRender={10} // 首次渲染数量
maxToRenderPerBatch={10} // 每批渲染数量
windowSize={21} // 渲染窗口大小
removeClippedSubviews={true} // 移除不可见视图
// 下拉刷新
refreshing={false}
onRefresh={() => {}}
// 加载更多
onEndReached={() => {}}
onEndReachedThreshold={0.5}
/>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 交互组件
# Button - 按钮
import { Button } from 'react-native';
<Button
title="Press Me"
onPress={() => console.log('Pressed')}
color="#841584"
disabled={false}
/>
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# TouchableOpacity - 可点击组件
import { TouchableOpacity, Text } from 'react-native';
<TouchableOpacity
activeOpacity={0.7}
onPress={() => console.log('Pressed')}
onLongPress={() => console.log('Long pressed')}
>
<Text>Custom Button</Text>
</TouchableOpacity>
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# TextInput - 文本输入
import { TextInput } from 'react-native';
const [text, setText] = useState('');
<TextInput
value={text}
onChangeText={setText}
placeholder="Enter text"
placeholderTextColor="#999"
keyboardType="default" // default | numeric | email-address | phone-pad
secureTextEntry={false} // 密码模式
multiline={false} // 多行输入
autoFocus={true}
maxLength={100}
/>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Switch - 开关
import { Switch } from 'react-native';
const [enabled, setEnabled] = useState(false);
<Switch
value={enabled}
onValueChange={setEnabled}
trackColor={{ false: '#767577', true: '#81b0ff' }}
thumbColor={enabled ? '#f5dd4b' : '#f4f3f4'}
/>
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 模态与提示
# Modal - 模态框
import { Modal, View, Text, Button } from 'react-native';
const [visible, setVisible] = useState(false);
<Modal
visible={visible}
animationType="slide" // slide | fade | none
transparent={true}
onRequestClose={() => setVisible(false)}
>
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<View style={{ backgroundColor: 'white', padding: 20 }}>
<Text>Modal Content</Text>
<Button title="Close" onPress={() => setVisible(false)} />
</View>
</View>
</Modal>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Alert - 警告框
import { Alert } from 'react-native';
// 简单提示
Alert.alert('Title', 'Message');
// 带按钮
Alert.alert(
'Confirm',
'Are you sure?',
[
{ text: 'Cancel', style: 'cancel' },
{ text: 'OK', onPress: () => console.log('OK') },
]
);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
# 4️⃣ 样式与布局
# StyleSheet API
import { StyleSheet } from 'react-native';
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
},
text: {
fontSize: 16,
color: '#333',
},
});
// 使用
<View style={styles.container}>
<Text style={styles.text}>Hello</Text>
</View>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
优势:
- ✅ 性能优化:样式对象只创建一次
- ✅ 代码提示:支持 TypeScript
- ✅ 验证:自动检测无效样式
# Flexbox 布局
// 主轴布局
<View style={{
flexDirection: 'row', // 主轴方向:row | column
justifyContent: 'flex-start', // flex-start | center | flex-end | space-between | space-around
alignItems: 'stretch', // flex-start | center | flex-end | stretch | baseline
flexWrap: 'nowrap', // nowrap | wrap | wrap-reverse
}}>
<View style={{ flex: 1 }} />
<View style={{ flex: 2 }} />
</View>
// 自适应布局
<View style={{
alignSelf: 'center', // 覆盖父容器的 alignItems
flexGrow: 1, // 增长因子
flexShrink: 1, // 收缩因子
flexBasis: 'auto', // 基准大小
}}>
</View>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 响应式布局
import { Dimensions, Platform } from 'react-native';
// 获取屏幕尺寸
const { width, height } = Dimensions.get('window');
const styles = StyleSheet.create({
container: {
width: width * 0.9, // 90% 宽度
padding: width > 768 ? 40 : 20, // iPad vs iPhone
},
});
// 监听尺寸变化
useEffect(() => {
const subscription = Dimensions.addEventListener('change', ({ window }) => {
console.log('New dimensions:', window);
});
return () => subscription?.remove();
}, []);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 平台特定样式
import { Platform, StyleSheet } from 'react-native';
const styles = StyleSheet.create({
container: {
...Platform.select({
ios: {
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.25,
shadowRadius: 3.84,
},
android: {
elevation: 5,
},
}),
},
});
// 或使用条件判断
Platform.OS === 'ios' ? iosStyles : androidStyles
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 动画样式
import { Animated } from 'react-native';
function FadeInView({ children }) {
const fadeAnim = useRef(new Animated.Value(0)).current;
useEffect(() => {
Animated.timing(fadeAnim, {
toValue: 1,
duration: 1000,
useNativeDriver: true,
}).start();
}, []);
return (
<Animated.View style={{ opacity: fadeAnim }}>
{children}
</Animated.View>
);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 5️⃣ 核心 API
# 平台信息
import { Platform } from 'react-native';
console.log(Platform.OS); // 'ios' | 'android'
console.log(Platform.Version); // iOS: '15.0' | Android: 31
console.log(Platform.isPad); // iPad 判断
console.log(Platform.isTV); // TV 判断
console.log(Platform.isTesting); // 测试环境判断
1
2
3
4
5
6
7
2
3
4
5
6
7
# 键盘管理
import { Keyboard } from 'react-native';
// 监听键盘事件
useEffect(() => {
const showListener = Keyboard.addListener('keyboardDidShow', (e) => {
console.log('Keyboard height:', e.endCoordinates.height);
});
const hideListener = Keyboard.addListener('keyboardDidHide', () => {
console.log('Keyboard hidden');
});
return () => {
showListener.remove();
hideListener.remove();
};
}, []);
// 手动控制
Keyboard.dismiss(); // 隐藏键盘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 权限管理
import { PermissionsAndroid } from 'react-native';
async function requestCameraPermission() {
try {
const granted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.CAMERA,
{
title: 'Camera Permission',
message: 'App needs camera access',
buttonNeutral: 'Ask Me Later',
buttonNegative: 'Cancel',
buttonPositive: 'OK',
}
);
if (granted === PermissionsAndroid.RESULTS.GRANTED) {
console.log('Camera permission granted');
}
} catch (err) {
console.warn(err);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 链接处理
import { Linking } from 'react-native';
// 打开 URL
Linking.openURL('https://google.com');
// 打开电话
Linking.openURL('tel:1234567890');
// 打开邮件
Linking.openURL('mailto:support@example.com');
// 检查是否可以打开
const supported = await Linking.canOpenURL(url);
// 监听 Deep Link
useEffect(() => {
const handleUrl = ({ url }) => {
console.log('Deep link:', url);
};
const subscription = Linking.addEventListener('url', handleUrl);
// 获取初始 URL
Linking.getInitialURL().then((url) => {
if (url) handleUrl({ url });
});
return () => subscription.remove();
}, []);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 异步存储
import AsyncStorage from '@react-native-async-storage/async-storage';
// 保存数据
await AsyncStorage.setItem('@key', 'value');
// 读取数据
const value = await AsyncStorage.getItem('@key');
// 保存对象
await AsyncStorage.setItem('@user', JSON.stringify({ name: 'John' }));
// 读取对象
const user = JSON.parse(await AsyncStorage.getItem('@user'));
// 删除
await AsyncStorage.removeItem('@key');
// 清空所有
await AsyncStorage.clear();
// 获取所有 key
const keys = await AsyncStorage.getAllKeys();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 网络状态
import NetInfo from '@react-native-community/netinfo';
// 获取当前状态
const state = await NetInfo.fetch();
console.log('Connected:', state.isConnected);
console.log('Type:', state.type); // wifi | cellular | bluetooth | ethernet
// 监听变化
const unsubscribe = NetInfo.addEventListener(state => {
console.log('Connection type:', state.type);
console.log('Is connected?', state.isConnected);
});
// 取消监听
unsubscribe();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 6️⃣ 导航与路由
# React Navigation
安装:
npm install @react-navigation/native
npm install react-native-screens react-native-safe-area-context
npm install @react-navigation/native-stack
1
2
3
2
3
# Stack Navigator - 堆栈导航
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
const Stack = createNativeStackNavigator();
function App() {
return (
<NavigationContainer>
<Stack.Navigator
initialRouteName="Home"
screenOptions={{
headerStyle: { backgroundColor: '#f4511e' },
headerTintColor: '#fff',
}}
>
<Stack.Screen
name="Home"
component={HomeScreen}
options={{ title: '首页' }}
/>
<Stack.Screen
name="Details"
component={DetailsScreen}
options={({ route }) => ({ title: route.params.name })}
/>
</Stack.Navigator>
</NavigationContainer>
);
}
// 导航跳转
function HomeScreen({ navigation }) {
return (
<Button
title="Go to Details"
onPress={() => navigation.navigate('Details', { id: 123 })}
/>
);
}
// 接收参数
function DetailsScreen({ route, navigation }) {
const { id } = route.params;
return <Text>Details ID: {id}</Text>;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# Tab Navigator - 底部标签导航
npm install @react-navigation/bottom-tabs
1
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import Icon from 'react-native-vector-icons/Ionicons';
const Tab = createBottomTabNavigator();
function MyTabs() {
return (
<Tab.Navigator
screenOptions={({ route }) => ({
tabBarIcon: ({ focused, color, size }) => {
let iconName;
if (route.name === 'Home') {
iconName = focused ? 'home' : 'home-outline';
} else if (route.name === 'Settings') {
iconName = focused ? 'settings' : 'settings-outline';
}
return <Icon name={iconName} size={size} color={color} />;
},
tabBarActiveTintColor: 'tomato',
tabBarInactiveTintColor: 'gray',
})}
>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Settings" component={SettingsScreen} />
</Tab.Navigator>
);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# Drawer Navigator - 抽屉导航
npm install @react-navigation/drawer
npm install react-native-gesture-handler react-native-reanimated
1
2
2
import { createDrawerNavigator } from '@react-navigation/drawer';
const Drawer = createDrawerNavigator();
function MyDrawer() {
return (
<Drawer.Navigator>
<Drawer.Screen name="Home" component={HomeScreen} />
<Drawer.Screen name="Profile" component={ProfileScreen} />
</Drawer.Navigator>
);
}
// 打开抽屉
navigation.openDrawer();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 7️⃣ 状态管理
# React Context
// 创建 Context
const ThemeContext = React.createContext('light');
// Provider
function App() {
const [theme, setTheme] = useState('light');
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
<HomeScreen />
</ThemeContext.Provider>
);
}
// 使用
function HomeScreen() {
const { theme, setTheme } = useContext(ThemeContext);
return (
<View style={{ backgroundColor: theme === 'dark' ? '#000' : '#fff' }}>
<Button
title="Toggle Theme"
onPress={() => setTheme(theme === 'dark' ? 'light' : 'dark')}
/>
</View>
);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# Redux Toolkit
npm install @reduxjs/toolkit react-redux
1
// store.js
import { configureStore, createSlice } from '@reduxjs/toolkit';
const counterSlice = createSlice({
name: 'counter',
initialState: { value: 0 },
reducers: {
increment: (state) => { state.value += 1; },
decrement: (state) => { state.value -= 1; },
},
});
export const { increment, decrement } = counterSlice.actions;
export const store = configureStore({
reducer: {
counter: counterSlice.reducer,
},
});
// App.js
import { Provider } from 'react-redux';
import { store } from './store';
function App() {
return (
<Provider store={store}>
<CounterScreen />
</Provider>
);
}
// CounterScreen.js
import { useSelector, useDispatch } from 'react-redux';
function CounterScreen() {
const count = useSelector((state) => state.counter.value);
const dispatch = useDispatch();
return (
<View>
<Text>{count}</Text>
<Button title="+" onPress={() => dispatch(increment())} />
<Button title="-" onPress={() => dispatch(decrement())} />
</View>
);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# Zustand (轻量级)
npm install zustand
1
import create from 'zustand';
const useStore = create((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 })),
}));
function Counter() {
const { count, increment, decrement } = useStore();
return (
<View>
<Text>{count}</Text>
<Button title="+" onPress={increment} />
<Button title="-" onPress={decrement} />
</View>
);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 8️⃣ 网络与数据
# Fetch API
// GET 请求
async function fetchData() {
try {
const response = await fetch('https://api.example.com/data');
const json = await response.json();
console.log(json);
} catch (error) {
console.error(error);
}
}
// POST 请求
async function postData() {
try {
const response = await fetch('https://api.example.com/data', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: 'John',
age: 30,
}),
});
const json = await response.json();
console.log(json);
} catch (error) {
console.error(error);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# Axios
npm install axios
1
import axios from 'axios';
// 创建实例
const api = axios.create({
baseURL: 'https://api.example.com',
timeout: 5000,
headers: {
'Content-Type': 'application/json',
},
});
// 请求拦截器
api.interceptors.request.use(
(config) => {
const token = await AsyncStorage.getItem('@token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
(error) => Promise.reject(error)
);
// 响应拦截器
api.interceptors.response.use(
(response) => response.data,
(error) => {
if (error.response?.status === 401) {
// 处理未授权
}
return Promise.reject(error);
}
);
// 使用
const data = await api.get('/users');
const result = await api.post('/users', { name: 'John' });
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# React Query
npm install @tanstack/react-query
1
import { QueryClient, QueryClientProvider, useQuery } from '@tanstack/react-query';
const queryClient = new QueryClient();
function App() {
return (
<QueryClientProvider client={queryClient}>
<UsersScreen />
</QueryClientProvider>
);
}
function UsersScreen() {
const { data, isLoading, error } = useQuery({
queryKey: ['users'],
queryFn: () => fetch('https://api.example.com/users').then(res => res.json()),
});
if (isLoading) return <Text>Loading...</Text>;
if (error) return <Text>Error: {error.message}</Text>;
return (
<FlatList
data={data}
renderItem={({ item }) => <Text>{item.name}</Text>}
/>
);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 9️⃣ 原生模块
# 调用原生模块
import { NativeModules } from 'react-native';
const { CalendarModule } = NativeModules;
// 调用原生方法
CalendarModule.createCalendarEvent('Party', 'My House');
1
2
3
4
5
6
2
3
4
5
6
# 创建原生模块 (iOS)
// CalendarModule.h
#import <React/RCTBridgeModule.h>
@interface CalendarModule : NSObject <RCTBridgeModule>
@end
// CalendarModule.m
#import "CalendarModule.h"
@implementation CalendarModule
RCT_EXPORT_MODULE();
RCT_EXPORT_METHOD(createCalendarEvent:(NSString *)title location:(NSString *)location)
{
NSLog(@"Creating event %@ at %@", title, location);
}
@end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 创建原生模块 (Android)
// CalendarModule.java
package com.yourapp;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
public class CalendarModule extends ReactContextBaseJavaModule {
CalendarModule(ReactApplicationContext context) {
super(context);
}
@Override
public String getName() {
return "CalendarModule";
}
@ReactMethod
public void createCalendarEvent(String title, String location) {
Log.d("CalendarModule", "Creating event " + title + " at " + location);
}
}
// MainApplication.java
@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new CalendarPackage() // 添加自定义包
);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 🔟 调试与优化
# 开发者菜单
iOS 模拟器: Cmd + D
Android 模拟器: Cmd + M (Mac) / Ctrl + M (Windows)
真机: 摇一摇设备
1
2
3
2
3
功能:
- Reload - 重新加载
- Debug - 开启调试
- Enable Fast Refresh - 快速刷新
- Show Inspector - 元素检查器
- Show Perf Monitor - 性能监控
# 调试工具
# 1. Chrome DevTools
# 开启调试后,访问
chrome://inspect
1
2
2
# 2. Flipper (推荐)
# 安装 Flipper
# https://fbflipper.com/
# 功能:
# - 网络请求查看
# - 布局检查器
# - 数据库查看
# - 日志查看
# - React DevTools
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 3. Reactotron
npm install --save-dev reactotron-react-native
1
import Reactotron from 'reactotron-react-native';
Reactotron
.configure()
.useReactNative()
.connect();
// 使用
Reactotron.log('Hello');
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 性能优化
# 1. 列表优化
// 使用 FlatList 替代 ScrollView
<FlatList
data={data}
renderItem={renderItem}
keyExtractor={(item) => item.id}
// 性能优化参数
initialNumToRender={10}
maxToRenderPerBatch={10}
windowSize={21}
removeClippedSubviews={true}
getItemLayout={(data, index) => ({
length: ITEM_HEIGHT,
offset: ITEM_HEIGHT * index,
index,
})}
/>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 2. 图片优化
// 使用 FastImage
import FastImage from 'react-native-fast-image';
<FastImage
source={{
uri: 'https://example.com/image.png',
priority: FastImage.priority.normal,
cache: FastImage.cacheControl.immutable,
}}
resizeMode={FastImage.resizeMode.contain}
/>
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# 3. 避免不必要的重渲染
// 使用 React.memo
const MyComponent = React.memo(({ data }) => {
return <Text>{data}</Text>;
}, (prevProps, nextProps) => {
return prevProps.data === nextProps.data;
});
// 使用 useMemo
const expensiveValue = useMemo(() => {
return computeExpensiveValue(a, b);
}, [a, b]);
// 使用 useCallback
const memoizedCallback = useCallback(() => {
doSomething(a, b);
}, [a, b]);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 4. 使用 Native Driver
// 启用原生动画驱动
Animated.timing(animatedValue, {
toValue: 1,
duration: 500,
useNativeDriver: true, // 重要!
}).start();
1
2
3
4
5
6
2
3
4
5
6
# 性能分析
import { unstable_enableLogBox } from 'react-native/Libraries/LogBox/LogBox';
// 启用性能监控
if (__DEV__) {
const { Systrace } = require('react-native/Libraries/Performance/Systrace');
Systrace.setEnabled(true);
}
// 测量渲染时间
console.time('render');
// ... 代码
console.timeEnd('render');
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# 1️⃣1️⃣ 实战项目
# Todo 应用示例
import React, { useState } from 'react';
import {
View,
Text,
TextInput,
TouchableOpacity,
FlatList,
StyleSheet,
} from 'react-native';
export default function TodoApp() {
const [todos, setTodos] = useState([]);
const [text, setText] = useState('');
const addTodo = () => {
if (text.trim()) {
setTodos([...todos, { id: Date.now().toString(), text, completed: false }]);
setText('');
}
};
const toggleTodo = (id) => {
setTodos(todos.map(todo =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
));
};
const deleteTodo = (id) => {
setTodos(todos.filter(todo => todo.id !== id));
};
const renderItem = ({ item }) => (
<View style={styles.todoItem}>
<TouchableOpacity onPress={() => toggleTodo(item.id)} style={{ flex: 1 }}>
<Text style={[styles.todoText, item.completed && styles.completed]}>
{item.text}
</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => deleteTodo(item.id)}>
<Text style={styles.deleteButton}>✕</Text>
</TouchableOpacity>
</View>
);
return (
<View style={styles.container}>
<Text style={styles.title}>Todo List</Text>
<View style={styles.inputContainer}>
<TextInput
style={styles.input}
value={text}
onChangeText={setText}
placeholder="Add a new todo"
onSubmitEditing={addTodo}
/>
<TouchableOpacity style={styles.addButton} onPress={addTodo}>
<Text style={styles.addButtonText}>+</Text>
</TouchableOpacity>
</View>
<FlatList
data={todos}
renderItem={renderItem}
keyExtractor={(item) => item.id}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#f5f5f5',
padding: 20,
},
title: {
fontSize: 32,
fontWeight: 'bold',
marginTop: 40,
marginBottom: 20,
},
inputContainer: {
flexDirection: 'row',
marginBottom: 20,
},
input: {
flex: 1,
backgroundColor: '#fff',
padding: 15,
borderRadius: 10,
marginRight: 10,
},
addButton: {
backgroundColor: '#007AFF',
width: 50,
height: 50,
borderRadius: 25,
justifyContent: 'center',
alignItems: 'center',
},
addButtonText: {
color: '#fff',
fontSize: 30,
},
todoItem: {
flexDirection: 'row',
backgroundColor: '#fff',
padding: 15,
borderRadius: 10,
marginBottom: 10,
alignItems: 'center',
},
todoText: {
fontSize: 16,
},
completed: {
textDecorationLine: 'line-through',
color: '#999',
},
deleteButton: {
color: '#ff3b30',
fontSize: 20,
fontWeight: 'bold',
},
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# 1️⃣2️⃣ 常见问题
# node 命令不识别问题
使用 Android Studio 打开项目,可能会出现 node 不识别的问题
解决方案:
- 打开
node_modules/@react-native-community/cli-platform-android/native_modules.gradle - 将
Runtime.getRuntime().exec方法的第二个参数替换为包含 node 的路径
String command = "node";
String path = "/path/to/directory"; // 替换为实际的路径
String[] envp = new String[] {"PATH=/usr/bin:/bin:/path/to/node_directory"}; // 替换为包含 node 的路径
Process process = Runtime.getRuntime().exec(command, envp, new File(path));
1
2
3
4
2
3
4
# Metro Bundler 端口占用
# 查找占用 8081 端口的进程
lsof -ti:8081
# 杀死进程
kill -9 $(lsof -ti:8081)
# 或指定其他端口
npx react-native start --port 8088
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# iOS 构建失败
# 清理缓存
cd ios
rm -rf Pods Podfile.lock
pod install
# 清理构建文件
cd ..
npx react-native clean
cd ios
xcodebuild clean
# 重新构建
npx react-native run-ios
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
# Android 构建失败
# 清理 Gradle 缓存
cd android
./gradlew clean
# 删除构建文件
rm -rf .gradle build
# 重新构建
cd ..
npx react-native run-android
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 热更新不生效
# 重启 Metro Bundler
npx react-native start --reset-cache
# 或在开发者菜单中选择 "Reload"
1
2
3
4
2
3
4
# 📚 学习资源
# 官方文档
# 推荐库
UI 组件库:
- React Native Paper (opens new window) - Material Design
- NativeBase (opens new window) - 跨平台 UI 组件
- React Native Elements (opens new window)
导航:
状态管理:
网络请求:
图标:
动画:
# 学习路径
graph TD
A[开始学习 React Native] --> B[掌握 React 基础]
B --> C[环境搭建]
C --> D[核心组件与 API]
D --> E[样式与布局]
E --> F[导航与路由]
F --> G[状态管理]
G --> H[网络请求]
H --> I[原生模块]
I --> J[调试与优化]
J --> K[实战项目]
K --> L[发布应用]
# 🎯 总结
React Native 是一个强大的跨平台移动开发框架,通过本指南你应该已经掌握了:
✅ 基础知识:环境搭建、核心概念、架构原理 ✅ 组件系统:基础组件、交互组件、列表优化 ✅ 样式布局:Flexbox、响应式、平台特定样式 ✅ 核心 API:平台信息、权限、存储、网络 ✅ 导航路由:Stack、Tab、Drawer 导航 ✅ 状态管理:Context、Redux、Zustand ✅ 网络数据:Fetch、Axios、React Query ✅ 性能优化:列表优化、图片优化、动画优化 ✅ 调试技巧:DevTools、Flipper、Reactotron
继续深入学习,多做实战项目,你将能够开发出高质量的跨平台移动应用!🚀
上次更新: 2025/10/26, 10:08:27