React Native 学习指南
React Native 是一个使用 React 和 JavaScript 构建原生移动应用的框架。它允许开发者使用相同的代码库为 iOS 和 Android 平台开发应用,同时保持原生性能。
🚀 快速开始
创建 React Native 项目
# 使用 React Native CLI
npx react-native@latest init MyApp
# 使用 Expo CLI (推荐新手)
npx create-expo-app@latest MyApp
# 使用 TypeScript 模板
npx react-native@latest init MyApp --template react-native-template-typescript基本项目结构
MyApp/
├── android/ # Android 原生代码
├── ios/ # iOS 原生代码
├── src/ # 源代码
│ ├── components/ # 组件
│ ├── screens/ # 页面
│ ├── navigation/ # 导航
│ ├── services/ # 服务
│ └── utils/ # 工具函数
├── App.js # 应用入口
├── package.json # 依赖配置
└── metro.config.js # Metro 配置📚 核心概念
基础组件
// App.js
import React from 'react';
import {
SafeAreaView,
ScrollView,
StatusBar,
StyleSheet,
Text,
View,
} from 'react-native';
export default function App() {
return (
<SafeAreaView style={styles.container}>
<StatusBar barStyle="dark-content" />
<ScrollView contentInsetAdjustmentBehavior="automatic">
<View style={styles.section}>
<Text style={styles.sectionTitle}>Welcome to React Native!</Text>
<Text style={styles.sectionDescription}>
Edit App.js to change this screen and then come back to see your edits.
</Text>
</View>
</ScrollView>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
},
section: {
marginTop: 32,
paddingHorizontal: 24,
},
sectionTitle: {
fontSize: 24,
fontWeight: '600',
color: '#000',
},
sectionDescription: {
marginTop: 8,
fontSize: 18,
fontWeight: '400',
color: '#666',
},
});常用组件
import React, { useState } from 'react';
import {
View,
Text,
TextInput,
TouchableOpacity,
Image,
FlatList,
Alert,
} from 'react-native';
export default function BasicComponents() {
const [text, setText] = useState('');
const [items, setItems] = useState(['Item 1', 'Item 2', 'Item 3']);
const addItem = () => {
if (text.trim()) {
setItems([...items, text]);
setText('');
}
};
const showAlert = () => {
Alert.alert('提示', '这是一个警告框', [
{ text: '取消', style: 'cancel' },
{ text: '确定', onPress: () => console.log('确定') },
]);
};
return (
<View style={{ flex: 1, padding: 20 }}>
{/* 文本输入 */}
<TextInput
style={{
borderWidth: 1,
borderColor: '#ccc',
padding: 10,
marginBottom: 10,
}}
placeholder="输入文本"
value={text}
onChangeText={setText}
/>
{/* 按钮 */}
<TouchableOpacity
style={{
backgroundColor: '#007AFF',
padding: 15,
borderRadius: 8,
marginBottom: 10,
}}
onPress={addItem}
>
<Text style={{ color: 'white', textAlign: 'center' }}>添加项目</Text>
</TouchableOpacity>
{/* 图片 */}
<Image
source={{ uri: 'https://reactnative.dev/img/tiny_logo.png' }}
style={{ width: 100, height: 100, marginBottom: 10 }}
/>
{/* 列表 */}
<FlatList
data={items}
keyExtractor={(item, index) => index.toString()}
renderItem={({ item }) => (
<Text style={{ padding: 10, borderBottomWidth: 1, borderBottomColor: '#eee' }}>
{item}
</Text>
)}
/>
{/* 警告框 */}
<TouchableOpacity
style={{
backgroundColor: '#FF3B30',
padding: 15,
borderRadius: 8,
marginTop: 10,
}}
onPress={showAlert}
>
<Text style={{ color: 'white', textAlign: 'center' }}>显示警告</Text>
</TouchableOpacity>
</View>
);
}⚡ 样式和布局
Flexbox 布局
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
export default function FlexboxExample() {
return (
<View style={styles.container}>
{/* 行布局 */}
<View style={styles.row}>
<View style={[styles.box, styles.red]} />
<View style={[styles.box, styles.green]} />
<View style={[styles.box, styles.blue]} />
</View>
{/* 列布局 */}
<View style={styles.column}>
<View style={[styles.box, styles.red]} />
<View style={[styles.box, styles.green]} />
<View style={[styles.box, styles.blue]} />
</View>
{/* 居中布局 */}
<View style={styles.center}>
<Text style={styles.text}>居中文本</Text>
</View>
{/* 绝对定位 */}
<View style={styles.absolute}>
<Text style={styles.text}>绝对定位</Text>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#f5f5f5',
},
row: {
flexDirection: 'row',
justifyContent: 'space-between',
padding: 20,
},
column: {
flexDirection: 'column',
alignItems: 'center',
padding: 20,
},
center: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
absolute: {
position: 'absolute',
top: 50,
right: 20,
backgroundColor: 'rgba(0,0,0,0.7)',
padding: 10,
borderRadius: 5,
},
box: {
width: 60,
height: 60,
borderRadius: 8,
},
red: {
backgroundColor: '#FF3B30',
},
green: {
backgroundColor: '#34C759',
},
blue: {
backgroundColor: '#007AFF',
},
text: {
color: 'white',
fontSize: 16,
fontWeight: 'bold',
},
});响应式设计
import React from 'react';
import { View, Text, StyleSheet, Dimensions } from 'react-native';
const { width, height } = Dimensions.get('window');
export default function ResponsiveDesign() {
return (
<View style={styles.container}>
<View style={styles.card}>
<Text style={styles.title}>响应式卡片</Text>
<Text style={styles.description}>
屏幕宽度: {width}px{'\n'}
屏幕高度: {height}px
</Text>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
padding: width * 0.05, // 5% 的屏幕宽度
backgroundColor: '#f5f5f5',
},
card: {
backgroundColor: 'white',
borderRadius: 12,
padding: 20,
shadowColor: '#000',
shadowOffset: {
width: 0,
height: 2,
},
shadowOpacity: 0.25,
shadowRadius: 3.84,
elevation: 5,
},
title: {
fontSize: Math.max(16, width * 0.04), // 最小 16px,最大 4% 屏幕宽度
fontWeight: 'bold',
marginBottom: 10,
},
description: {
fontSize: Math.max(14, width * 0.035),
color: '#666',
lineHeight: 20,
},
});🎯 导航系统
React Navigation
# 安装导航库
npm install @react-navigation/native @react-navigation/stack @react-navigation/bottom-tabs
npm install react-native-screens react-native-safe-area-context// App.js
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import HomeScreen from './src/screens/HomeScreen';
import ProfileScreen from './src/screens/ProfileScreen';
import SettingsScreen from './src/screens/SettingsScreen';
import DetailScreen from './src/screens/DetailScreen';
const Stack = createStackNavigator();
const Tab = createBottomTabNavigator();
function TabNavigator() {
return (
<Tab.Navigator>
<Tab.Screen
name="Home"
component={HomeScreen}
options={{
title: '首页',
tabBarIcon: ({ color, size }) => (
<Text style={{ color, fontSize: size }}>🏠</Text>
),
}}
/>
<Tab.Screen
name="Profile"
component={ProfileScreen}
options={{
title: '个人',
tabBarIcon: ({ color, size }) => (
<Text style={{ color, fontSize: size }}>👤</Text>
),
}}
/>
<Tab.Screen
name="Settings"
component={SettingsScreen}
options={{
title: '设置',
tabBarIcon: ({ color, size }) => (
<Text style={{ color, fontSize: size }}>⚙️</Text>
),
}}
/>
</Tab.Navigator>
);
}
export default function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="Main"
component={TabNavigator}
options={{ headerShown: false }}
/>
<Stack.Screen
name="Detail"
component={DetailScreen}
options={{ title: '详情' }}
/>
</Stack.Navigator>
</NavigationContainer>
);
}页面组件
// src/screens/HomeScreen.js
import React from 'react';
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
export default function HomeScreen({ navigation }) {
return (
<View style={styles.container}>
<Text style={styles.title}>首页</Text>
<TouchableOpacity
style={styles.button}
onPress={() => navigation.navigate('Detail', { id: 1 })}
>
<Text style={styles.buttonText}>跳转到详情</Text>
</TouchableOpacity>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
padding: 20,
},
title: {
fontSize: 24,
fontWeight: 'bold',
marginBottom: 20,
},
button: {
backgroundColor: '#007AFF',
padding: 15,
borderRadius: 8,
},
buttonText: {
color: 'white',
fontSize: 16,
fontWeight: 'bold',
},
});// src/screens/DetailScreen.js
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
export default function DetailScreen({ route }) {
const { id } = route.params;
return (
<View style={styles.container}>
<Text style={styles.title}>详情页面</Text>
<Text style={styles.description}>ID: {id}</Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
padding: 20,
},
title: {
fontSize: 24,
fontWeight: 'bold',
marginBottom: 10,
},
description: {
fontSize: 16,
color: '#666',
},
});🔧 状态管理
Context API
// src/contexts/AppContext.js
import React, { createContext, useContext, useState } from 'react';
const AppContext = createContext();
export function AppProvider({ children }) {
const [user, setUser] = useState(null);
const [theme, setTheme] = useState('light');
const login = (userData) => {
setUser(userData);
};
const logout = () => {
setUser(null);
};
const toggleTheme = () => {
setTheme(theme === 'light' ? 'dark' : 'light');
};
return (
<AppContext.Provider value={{
user,
theme,
login,
logout,
toggleTheme,
}}>
{children}
</AppContext.Provider>
);
}
export function useApp() {
const context = useContext(AppContext);
if (!context) {
throw new Error('useApp must be used within AppProvider');
}
return context;
}使用 Context
// src/screens/ProfileScreen.js
import React from 'react';
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
import { useApp } from '../contexts/AppContext';
export default function ProfileScreen() {
const { user, theme, logout, toggleTheme } = useApp();
return (
<View style={[styles.container, { backgroundColor: theme === 'dark' ? '#000' : '#fff' }]}>
<Text style={[styles.title, { color: theme === 'dark' ? '#fff' : '#000' }]}>
个人资料
</Text>
{user ? (
<View>
<Text style={[styles.text, { color: theme === 'dark' ? '#fff' : '#000' }]}>
用户名: {user.name}
</Text>
<Text style={[styles.text, { color: theme === 'dark' ? '#fff' : '#000' }]}>
邮箱: {user.email}
</Text>
<TouchableOpacity style={styles.button} onPress={logout}>
<Text style={styles.buttonText}>退出登录</Text>
</TouchableOpacity>
</View>
) : (
<Text style={[styles.text, { color: theme === 'dark' ? '#fff' : '#000' }]}>
请先登录
</Text>
)}
<TouchableOpacity style={styles.themeButton} onPress={toggleTheme}>
<Text style={styles.buttonText}>
切换主题 ({theme})
</Text>
</TouchableOpacity>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
},
title: {
fontSize: 24,
fontWeight: 'bold',
marginBottom: 20,
},
text: {
fontSize: 16,
marginBottom: 10,
},
button: {
backgroundColor: '#FF3B30',
padding: 15,
borderRadius: 8,
marginTop: 20,
},
themeButton: {
backgroundColor: '#007AFF',
padding: 15,
borderRadius: 8,
marginTop: 20,
},
buttonText: {
color: 'white',
textAlign: 'center',
fontSize: 16,
fontWeight: 'bold',
},
});📦 网络请求
Fetch API
// src/services/api.js
const BASE_URL = 'https://api.example.com';
export const api = {
async get(endpoint) {
try {
const response = await fetch(`${BASE_URL}${endpoint}`);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
} catch (error) {
console.error('API Error:', error);
throw error;
}
},
async post(endpoint, data) {
try {
const response = await fetch(`${BASE_URL}${endpoint}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
} catch (error) {
console.error('API Error:', error);
throw error;
}
},
};使用 API
// src/screens/PostsScreen.js
import React, { useState, useEffect } from 'react';
import {
View,
Text,
FlatList,
TouchableOpacity,
StyleSheet,
ActivityIndicator,
} from 'react-native';
import { api } from '../services/api';
export default function PostsScreen({ navigation }) {
const [posts, setPosts] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
fetchPosts();
}, []);
const fetchPosts = async () => {
try {
setLoading(true);
const data = await api.get('/posts');
setPosts(data);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
};
const renderPost = ({ item }) => (
<TouchableOpacity
style={styles.postItem}
onPress={() => navigation.navigate('Detail', { post: item })}
>
<Text style={styles.postTitle}>{item.title}</Text>
<Text style={styles.postExcerpt}>{item.body}</Text>
</TouchableOpacity>
);
if (loading) {
return (
<View style={styles.center}>
<ActivityIndicator size="large" color="#007AFF" />
</View>
);
}
if (error) {
return (
<View style={styles.center}>
<Text style={styles.error}>错误: {error}</Text>
<TouchableOpacity style={styles.button} onPress={fetchPosts}>
<Text style={styles.buttonText}>重试</Text>
</TouchableOpacity>
</View>
);
}
return (
<View style={styles.container}>
<FlatList
data={posts}
renderItem={renderPost}
keyExtractor={(item) => item.id.toString()}
refreshing={loading}
onRefresh={fetchPosts}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#f5f5f5',
},
center: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
postItem: {
backgroundColor: 'white',
padding: 15,
marginHorizontal: 15,
marginVertical: 5,
borderRadius: 8,
shadowColor: '#000',
shadowOffset: {
width: 0,
height: 1,
},
shadowOpacity: 0.22,
shadowRadius: 2.22,
elevation: 3,
},
postTitle: {
fontSize: 18,
fontWeight: 'bold',
marginBottom: 5,
},
postExcerpt: {
fontSize: 14,
color: '#666',
},
error: {
color: '#FF3B30',
fontSize: 16,
marginBottom: 20,
},
button: {
backgroundColor: '#007AFF',
padding: 15,
borderRadius: 8,
},
buttonText: {
color: 'white',
fontSize: 16,
fontWeight: 'bold',
},
});🛠️ 原生模块集成
相机功能
# 安装相机库
npm install react-native-camera// src/components/CameraComponent.js
import React, { useState } from 'react';
import { View, TouchableOpacity, Text, StyleSheet } from 'react-native';
import { RNCamera } from 'react-native-camera';
export default function CameraComponent() {
const [camera, setCamera] = useState(null);
const takePicture = async () => {
if (camera) {
try {
const options = { quality: 0.5, base64: true };
const data = await camera.takePictureAsync(options);
console.log('Photo taken:', data.uri);
} catch (error) {
console.error('Camera error:', error);
}
}
};
return (
<View style={styles.container}>
<RNCamera
ref={(ref) => setCamera(ref)}
style={styles.camera}
type={RNCamera.Constants.Type.back}
flashMode={RNCamera.Constants.FlashMode.off}
androidCameraPermissionOptions={{
title: '相机权限',
message: '需要相机权限来拍照',
buttonPositive: '确定',
buttonNegative: '取消',
}}
>
<View style={styles.buttonContainer}>
<TouchableOpacity onPress={takePicture} style={styles.captureButton}>
<Text style={styles.captureText}>拍照</Text>
</TouchableOpacity>
</View>
</RNCamera>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
camera: {
flex: 1,
},
buttonContainer: {
flex: 1,
backgroundColor: 'transparent',
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'flex-end',
marginBottom: 20,
},
captureButton: {
backgroundColor: '#007AFF',
padding: 15,
borderRadius: 50,
width: 80,
height: 80,
justifyContent: 'center',
alignItems: 'center',
},
captureText: {
color: 'white',
fontSize: 14,
fontWeight: 'bold',
},
});📖 学习资源
官方文档
实用工具和库
- Expo: 开发工具和服务
- React Navigation: 导航库
- Redux Toolkit: 状态管理
- React Native Elements: UI 组件库
- React Native Vector Icons: 图标库
🔍 调试工具
- React Native Debugger: 调试工具
- Flipper: 移动应用调试平台
- Metro: JavaScript 打包工具
最后更新: 2024年
最近更新:12/9/2025, 2:17:55 AM