React Native 从入门到深入(2025 最新版)
前言
本文基于 React Native 0.74+(2025 稳定版),适配 React 18 特性,从「环境搭建→基础语法→框架设计→底层原理→实战优化」逐步递进,既适合自学,也适合向入门者讲解(每个知识点包含「是什么→为什么→怎么用」,配合实例和通俗解释)。
核心目标:
- 让入门者掌握 RN 开发全流程,能独立开发跨平台 App;
- 理解 RN 跨平台原理,避免「只会用不会懂」;
- 覆盖最新特性(Hermes 引擎、新架构、React 18 并发渲染)。

第一部分:入门基础(写给新手,1 周上手)
1.1 什么是 React Native?
核心定义
React Native(简称 RN)是 Facebook 推出的跨平台移动应用开发框架,基于 React 语法,通过「JS/TS 编写代码,编译为原生组件」实现 iOS/Android 一套代码运行。
和传统方案的区别
| 方案 | 原理 | 优势 | 劣势 |
|---|---|---|---|
| RN(跨平台原生) | JS 驱动原生组件渲染 | 性能接近原生、跨平台率高 | 复杂原生功能需桥接 |
| 原生开发(iOS/Android) | 分别用 Swift/Java 编写 | 性能最优、功能无限制 | 两套代码、开发效率低 |
| H5/混合开发(Cordova) | WebView 渲染 | 开发快、跨平台率 100% | 性能差、原生交互弱 |
核心优势
- 「一次编写,两处运行」:90%+ 代码复用,减少 iOS/Android 双端开发成本;
- 「React 语法复用」:会 React 网页开发,上手 RN 成本极低;
- 「性能接近原生」:通过原生组件渲染(非 WebView),流畅度远超混合开发;
- 「热更新支持」:无需上架应用商店,通过 CodePush 快速修复 bug。
1.2 环境搭建(最新稳定版)
RN 环境搭建是新手第一个拦路虎,重点讲「官方 CLI 方案」(生产级)和「Expo 方案」(快速尝鲜)。
前置依赖(必装)
| 系统 | 必需工具 |
|---|---|
| macOS | Node.js 18+、JDK 17+、Android Studio(Android 开发)、Xcode 15+(iOS 开发) |
| Windows | Node.js 18+、JDK 17+、Android Studio(仅支持 Android 开发) |
注意:Node.js 必须 18+(RN 0.74+ 最低要求),JDK 必须 17+(Android Gradle 8.0+ 要求)
方案 1:Expo 快速尝鲜(推荐新手入门)
Expo 是 RN 的「开发工具集」,简化环境配置,无需手动装 Android Studio/Xcode 复杂依赖。
步骤:
-
安装 Expo CLI:
bashnpm install -g expo-cli -
创建项目:
bashexpo init MyFirstRNApp # 选择模板:blank(空白模板) -
启动项目:
bashcd MyFirstRNApp npm start # 启动 Metro 打包器(RN 核心打包工具) -
预览效果:
- 手机安装「Expo Go」App(应用商店搜索);
- 扫描终端的 QR 码,即可实时预览 App。
方案 2:官方 CLI 方案(生产环境使用)
适合需要自定义原生代码(如集成第三方 SDK)的场景,步骤更繁琐但更灵活。
步骤 1:安装依赖
-
Node.js 18+:官网下载 https://nodejs.org/,安装后验证:
bashnode -v # 输出 v18.x.x 即可 -
JDK 17+:官网下载 https://www.oracle.com/java/technologies/downloads/,配置环境变量
JAVA_HOME; -
Android Studio:
- 安装后打开「SDK Manager」,勾选:
- Android SDK Platform 34(RN 0.74+ 推荐)
- Android SDK Build-Tools 34
- Android Emulator
- 配置环境变量
ANDROID_HOME(指向 SDK 安装目录)。
- 安装后打开「SDK Manager」,勾选:
-
Xcode(macOS 仅):
- 安装后打开「Preferences → Locations」,选择 Xcode 版本;
- 运行
xcodebuild -runFirstLaunch初始化。
步骤 2:创建项目
bash
# 安装 RN CLI(全局)
npm install -g react-native-cli
# 创建项目(指定 0.74.0 版本)
react-native init MyRNProject --version 0.74.0
步骤 3:运行项目
-
Android:
bash# 启动模拟器(或连接真机,开启 USB 调试) react-native run-android -
iOS(macOS 仅):
bash# 安装 Pod 依赖(iOS 必需) cd ios && pod install && cd .. # 启动模拟器(或连接真机) react-native run-ios
常见问题:
- 模拟器启动失败:检查 HAXM 虚拟化是否开启(Android Studio → SDK Manager → SDK Tools);
- iOS Pod 安装失败:更新 CocoaPods 到最新版(
sudo gem install cocoapods);- 编译报错:检查 Node/JDK/SDK 版本是否匹配。
1.3 第一个 RN 程序:Hello World 深度解析
创建项目后,打开 App.js(核心入口文件),默认代码如下,逐行解析:
jsx
// 1. 导入依赖:React 核心 + RN 基础组件
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
// 2. 定义函数组件(React 18 推荐,替代类组件)
const App = () => {
// 3. 返回 JSX 结构(RN 的 UI 描述语法)
return (
// View:相当于网页的 div,容器组件,无视觉样式
<View style={styles.container}>
// Text:文本组件,RN 中所有文字必须放在 Text 内(区别于网页)
<Text style={styles.text}>Hello React Native 2025!</Text>
</View>
);
};
// 4. 样式定义:StyleSheet.create 优化性能(类似 CSS,但语法是 JS 对象)
const styles = StyleSheet.create({
container: {
flex: 1, // 占满父容器所有空间(Flexbox 布局核心)
justifyContent: 'center', // 水平居中(主轴:默认垂直)
alignItems: 'center', // 垂直居中(交叉轴)
backgroundColor: '#f5f5f5', // 背景色
},
text: {
fontSize: 20, // 字体大小(无单位,RN 自动适配设备像素)
color: '#333', // 字体颜色
fontWeight: '600', // 字体粗细(600 对应 semi-bold)
},
});
// 5. 导出组件(供入口文件引用)
export default App;
核心知识点(新手必记)
- JSX 语法规则 :
- 标签必须闭合(如
<View></View>,不能<View>); - 样式用
style属性,值是 JS 对象或 StyleSheet 引用; - 没有 HTML 标签,只有 RN 内置组件(View/Text/Image 等)。
- 标签必须闭合(如
- StyleSheet 优势 :
- 性能优化:提前验证样式合法性,避免运行时错误;
- 代码复用:样式可抽离为公共文件,全局复用。
- Flexbox 布局 :
- RN 中所有容器默认是
flex: 0,flex: 1表示占满剩余空间; - 主轴默认是「垂直方向」(区别于网页的水平方向),
flexDirection: 'row'可修改。
- RN 中所有容器默认是
1.4 基础组件与样式(实战必备)
RN 的 UI 构建依赖「组件 + 样式」,以下是最常用的基础组件和样式技巧。
1.4.1 核心内置组件
| 组件 | 作用 | 关键属性 |
|---|---|---|
| View | 容器(类似 div) | style、onLayout(布局变化回调) |
| Text | 文本显示 | style、numberOfLines(最大行数) |
| Image | 图片加载 | source(资源路径)、style |
| TextInput | 输入框 | value、onChangeText、placeholder |
| TouchableOpacity | 可点击组件(点击时透明) | onPress(点击回调)、activeOpacity |
1.4.2 组件使用示例(Todo 输入框)
jsx
import React, { useState } from 'react';
import { View, Text, TextInput, TouchableOpacity, StyleSheet } from 'react-native';
const TodoInput = () => {
// 状态管理:useState 存储输入框内容(React 核心 Hooks)
const [inputText, setInputText] = useState('');
// 点击按钮回调
const handleAddTodo = () => {
if (inputText.trim()) {
alert(`添加 Todo:${inputText}`);
setInputText(''); // 清空输入框
}
};
return (
<View style={styles.container}>
{/* 输入框 */}
<TextInput
style={styles.input}
value={inputText}
onChangeText={setInputText} // 输入变化时更新状态
placeholder="请输入 Todo 内容"
placeholderTextColor="#999"
autoCapitalize="none" // 关闭自动大写
/>
{/* 按钮 */}
<TouchableOpacity style={styles.button} onPress={handleAddTodo}>
<Text style={styles.buttonText}>添加</Text>
</TouchableOpacity>
</View>
);
};
const styles = StyleSheet.create({
container: {
flexDirection: 'row', // 横向排列(主轴改为水平)
padding: 16,
gap: 8, // 组件间距(RN 0.71+ 支持,替代 margin)
},
input: {
flex: 1, // 占满剩余空间
height: 44,
borderWidth: 1,
borderColor: '#ddd',
borderRadius: 8,
paddingHorizontal: 12,
fontSize: 16,
},
button: {
backgroundColor: '#2196F3',
paddingHorizontal: 16,
borderRadius: 8,
justifyContent: 'center',
alignItems: 'center',
},
buttonText: {
color: 'white',
fontSize: 16,
fontWeight: '500',
},
});
export default TodoInput;
1.4.3 样式核心技巧
-
单位问题 :RN 中样式无单位(如
fontSize: 16),自动适配设备像素密度(dp); -
样式继承 :只有 Text 组件支持样式继承(如父 Text 设置
color: red,子 Text 会继承),View 不支持; -
条件样式 :通过三元表达式动态切换样式:
jsx<View style={[styles.box, isActive ? styles.activeBox : null]} /> -
全局样式 :抽离公共样式到
styles/common.js,全局导入使用:jsx// common.js export const commonStyles = StyleSheet.create({ container: { flex: 1, padding: 16, backgroundColor: '#f5f5f5', }, }); // 组件中使用 import { commonStyles } from './styles/common'; <View style={commonStyles.container} />
1.5 状态管理与生命周期(React 核心)
RN 基于 React,状态管理和生命周期完全复用 React 逻辑,重点掌握「Hooks 语法」(React 18 推荐,替代类组件)。
1.5.1 核心 Hooks 详解
| Hooks | 作用 | 示例场景 |
|---|---|---|
| useState | 管理组件内部状态 | 输入框内容、开关状态、列表数据 |
| useEffect | 处理副作用(请求、订阅、DOM 操作) | 页面加载时请求数据、监听状态变化 |
| useContext | 跨组件共享状态 | 主题切换、用户登录状态 |
1.5.2 实战示例:Todo 列表(useState + useEffect)
jsx
import React, { useState, useEffect } from 'react';
import { View, Text, FlatList, StyleSheet } from 'react-native';
import TodoInput from './TodoInput';
const TodoList = () => {
// 状态:存储 Todo 列表(数组)
const [todos, setTodos] = useState([]);
// 副作用:页面加载时初始化 Todo 数据(模拟接口请求)
useEffect(() => {
// 模拟异步请求(300ms 后返回数据)
const timer = setTimeout(() => {
setTodos([
{ id: '1', text: '学习 RN 基础语法' },
{ id: '2', text: '理解 Flexbox 布局' },
]);
}, 300);
// 清理函数:组件卸载时清除定时器(避免内存泄漏)
return () => clearTimeout(timer);
}, []); // 依赖数组为空:仅在组件挂载时执行一次
// 添加 Todo 函数(传递给 TodoInput 组件)
const addTodo = (text) => {
const newTodo = { id: Date.now().toString(), text };
setTodos([...todos, newTodo]); // 不可变更新(不能直接 push)
};
// 渲染每个 Todo 项
const renderTodoItem = ({ item }) => (
<View style={styles.todoItem}>
<Text style={styles.todoText}>{item.text}</Text>
</View>
);
return (
<View style={styles.container}>
<Text style={styles.title}>我的 Todo 列表</Text>
<TodoInput onAddTodo={addTodo} />
{/* FlatList:高效渲染长列表(替代 ScrollView,避免性能问题) */}
<FlatList
data={todos}
renderItem={renderTodoItem}
keyExtractor={(item) => item.id} // 必须:每个项的唯一标识
style={styles.list}
emptyComponent={<Text style={styles.emptyText}>暂无 Todo 数据</Text>}
/>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#f5f5f5',
},
title: {
fontSize: 22,
fontWeight: '600',
padding: 16,
color: '#333',
},
list: {
flex: 1,
paddingHorizontal: 16,
},
todoItem: {
backgroundColor: 'white',
padding: 12,
borderRadius: 8,
marginBottom: 8,
},
todoText: {
fontSize: 16,
color: '#333',
},
emptyText: {
textAlign: 'center',
marginTop: 32,
color: '#999',
fontSize: 16,
},
});
export default TodoList;
1.5.3 关键知识点
-
不可变更新 :React 状态是只读的,更新数组/对象时不能直接修改原数据,需用「扩展运算符」或
immer库:jsx// 错误:直接修改原数组 todos.push(newTodo); // 正确:不可变更新 setTodos([...todos, newTodo]); -
useEffect 依赖数组 :
- 依赖数组为空
[]:仅组件挂载时执行一次; - 依赖数组有值
[todos]:组件挂载 + 依赖项变化时执行; - 无依赖数组:每次组件渲染都执行。
- 依赖数组为空
-
FlatList vs ScrollView :
- ScrollView:一次性渲染所有子组件,适合短列表;
- FlatList:懒加载渲染(只渲染可视区域组件),适合长列表(避免性能问题)。
1.6 路由管理(React Navigation 6.x)
RN 没有内置路由,需使用第三方库 react-navigation(最新版 6.x),实现页面跳转、传参、底部导航等功能。
1.6.1 安装依赖
bash
# 安装核心库
npm install @react-navigation/native@6.x
# 安装依赖(RN 0.60+ 自动链接,无需额外配置)
npm install react-native-screens react-native-safe-area-context
# 安装导航栈(Stack Navigator)
npm install @react-navigation/stack@6.x
# 安装底部标签导航(Tab Navigator,可选)
npm install @react-navigation/bottom-tabs@6.x
1.6.2 基础路由配置(Stack Navigator)
jsx
// App.js
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import TodoList from './TodoList';
import TodoDetail from './TodoDetail'; // 待创建的详情页
// 创建栈导航器
const Stack = createStackNavigator();
const App = () => {
return (
// 导航容器:所有导航组件的根组件
<NavigationContainer>
<Stack.Navigator
// 初始页面配置
initialRouteName="TodoList"
// 全局导航栏样式
screenOptions={{
headerStyle: { backgroundColor: '#2196F3' },
headerTintColor: 'white',
headerTitleStyle: { fontSize: 18, fontWeight: '600' },
}}
>
{/* 配置页面路由 */}
<Stack.Screen
name="TodoList" // 路由名称(唯一)
component={TodoList} // 对应的组件
options={{ title: 'Todo 列表' }} // 页面标题
/>
<Stack.Screen
name="TodoDetail"
component={TodoDetail}
// 动态标题(从参数中获取)
options={({ route }) => ({ title: route.params.todo.text })}
/>
</Stack.Navigator>
</NavigationContainer>
);
};
export default App;
1.6.3 页面跳转与传参
jsx
// TodoList.js 中添加跳转逻辑
const renderTodoItem = ({ item, navigation }) => (
<TouchableOpacity style={styles.todoItem} onPress={() => {
// 跳转至详情页,并传递参数
navigation.navigate('TodoDetail', { todo: item });
}}>
<Text style={styles.todoText}>{item.text}</Text>
</TouchableOpacity>
);
// TodoDetail.js 接收参数
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
const TodoDetail = ({ route }) => {
// 从 route.params 中获取传递的参数
const { todo } = route.params;
return (
<View style={styles.container}>
<Text style={styles.title}>Todo 详情</Text>
<Text style={styles.content}>{todo.text}</Text>
<Text style={styles.id}>ID: {todo.id}</Text>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 16,
backgroundColor: '#f5f5f5',
},
title: {
fontSize: 20,
fontWeight: '600',
marginBottom: 24,
},
content: {
fontSize: 18,
color: '#333',
marginBottom: 16,
},
id: {
fontSize: 14,
color: '#999',
},
});
export default TodoDetail;
1.6.4 底部标签导航(Tab Navigator)
实现类似微信的底部导航栏:
jsx
// App.js 中修改
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import Ionicons from 'react-native-vector-icons/Ionicons'; // 图标库(需安装:npm install react-native-vector-icons)
const Tab = createBottomTabNavigator();
const App = () => {
return (
<NavigationContainer>
<Tab.Navigator
screenOptions={({ route }) => ({
// 底部标签图标
tabBarIcon: ({ focused, color, size }) => {
let iconName;
if (route.name === 'TodoList') {
iconName = focused ? 'list' : 'list-outline';
} else if (route.name === 'Setting') {
iconName = focused ? 'settings' : 'settings-outline';
}
return <Ionicons name={iconName} size={size} color={color} />;
},
tabBarActiveTintColor: '#2196F3', // 选中颜色
tabBarInactiveTintColor: '#999', // 未选中颜色
})}
>
<Tab.Screen name="TodoList" component={TodoListStack} />
<Tab.Screen name="Setting" component={Setting} />
</Tab.Navigator>
</NavigationContainer>
);
};
第二部分:框架设计(进阶理解,知其然知其所以然)
2.1 RN 核心设计思想
2.1.1 跨平台核心:「一次编写,原生渲染」
RN 的核心不是「模拟原生」,而是「通过 JS 驱动原生组件渲染」,其设计思想可总结为:
- UI 描述与渲染分离:JS 侧用 JSX 描述 UI 结构,原生侧负责渲染;
- 桥接机制:JS 侧和原生侧通过「桥接(Bridge)」通信(新架构中已替换为 JSI);
- 组件映射:RN 内置组件(View/Text/Image)对应原生组件(iOS 的 UIView/UILabel/UIImageView,Android 的 View/TextView/ImageView)。
2.1.2 虚拟 DOM(React 核心)
RN 复用 React 的虚拟 DOM 机制,解决「频繁操作原生组件导致的性能问题」:
- 虚拟 DOM 是什么 :内存中的 JS 对象,描述 UI 结构(如
<View><Text></Text></View>对应一个对象树); - Diff 算法:当状态变化时,React 对比新旧虚拟 DOM,计算出「最小更新差异」;
- 批量更新:将差异批量同步到原生侧,减少原生组件的频繁重绘。
2.1.3 新架构 vs 旧架构(2025 重点)
RN 0.68+ 推出「新架构」,逐步替代旧架构,核心改进如下:
| 对比维度 | 旧架构(Bridge) | 新架构(Fabric + TurboModules) |
|---|---|---|
| 通信方式 | 异步序列化(JSON 格式) | 同步调用(JSI 直接调用原生方法) |
| UI 渲染 | 批量异步渲染 | 同步渲染(支持并发渲染) |
| 原生模块调用 | 异步回调 | 同步调用(支持 Promise) |
| 性能 | 中(序列化/反序列化耗时) | 高(减少中间开销) |
| 兼容性 | 好(稳定) | 逐步完善(2025 已稳定) |
新架构核心组件:
- JSI(JavaScript Interface):JS 直接调用原生 C++ 方法,替代 Bridge;
- Fabric:新的 UI 渲染层,支持同步渲染和 React 18 并发特性;
- TurboModules:新的原生模块系统,支持类型安全和同步调用;
- Codegen:代码生成工具,将 JS 接口定义转换为原生代码(C++/Swift/Java)。
2.2 RN 组件系统设计
RN 的组件系统遵循「组合优于继承」的设计原则,分为以下几类:
2.2.1 组件分类
- 内置基础组件:View/Text/Image 等,直接映射原生组件(核心);
- 复合组件:由基础组件组合而成(如 TodoItem、TodoInput),复用逻辑;
- 原生组件:自定义原生 UI 组件(如地图、播放器),通过桥接(或 TurboModules)暴露给 JS 侧;
- 第三方组件 :社区开源组件(如
react-native-image-picker图片选择器),需安装依赖并链接原生代码。
2.2.2 组件生命周期(函数组件 + Hooks)
React 18 中,函数组件通过 useEffect 覆盖类组件的生命周期,对应关系如下:
| 类组件生命周期 | 函数组件 Hooks 实现 |
|---|---|
| componentDidMount | useEffect(() => {}, []) |
| componentDidUpdate | useEffect(() => {}, [依赖项]) |
| componentWillUnmount | useEffect(() => { return 清理函数 }, []) |
| shouldComponentUpdate | React.memo(组件记忆化) |
示例:组件挂载时订阅事件,卸载时取消订阅:
jsx
useEffect(() => {
const subscription = someEventEmitter.addListener('event', handleEvent);
return () => subscription.remove(); // 卸载时取消订阅
}, []);
2.2.3 组件优化:React.memo + useMemo + useCallback
当组件频繁渲染时,需通过以下 Hooks 优化性能:
-
React.memo :记忆化组件,避免 props 未变化时重新渲染;
jsx// 仅当 props.todo 变化时,TodoItem 才重新渲染 const TodoItem = React.memo(({ todo, onPress }) => { return <TouchableOpacity onPress={onPress}>{todo.text}</TouchableOpacity>; }); -
useMemo :记忆化计算结果,避免每次渲染重复计算;
jsx// 仅当 todos 变化时,才重新计算已完成的 Todo 数量 const completedCount = useMemo(() => { return todos.filter(todo => todo.completed).length; }, [todos]); -
useCallback :记忆化函数,避免每次渲染创建新函数(导致子组件 props 变化);
jsx// 仅当 addTodo 逻辑不变时,函数引用不变 const handleAddTodo = useCallback((text) => { setTodos([...todos, { id: Date.now().toString(), text }]); }, [todos]);
2.3 状态管理设计(从简单到复杂)
RN 中的状态管理分为「组件内部状态」和「全局状态」,根据项目复杂度选择方案:
2.3.1 状态管理方案对比
| 方案 | 适用场景 | 优势 | 劣势 |
|---|---|---|---|
| useState + useContext | 小型项目、简单全局状态 | 无需第三方库、原生支持 | 不适合复杂状态逻辑(如异步) |
| Redux Toolkit | 中大型项目、复杂状态逻辑 | 生态完善、调试工具丰富 | 配置繁琐(需 Provider/Reducer) |
| Zustand | 中大型项目、追求简洁 | API 简洁、无需 Provider | 生态不如 Redux 完善 |
| Jotai/Recoil | 原子化状态、细粒度更新 | 性能优、支持 Suspense | 学习成本略高 |
2.3.2 实战:Zustand 全局状态管理(2025 热门方案)
Zustand 是轻量级全局状态库,API 简洁,无需 Provider 包裹,适合大多数项目。
-
安装:
bashnpm install zustand -
创建全局状态(
store/todoStore.js):jsximport { create } from 'zustand'; // 创建 store const useTodoStore = create((set) => ({ // 状态:Todo 列表 todos: [], // 动作:添加 Todo addTodo: (text) => set((state) => ({ todos: [...state.todos, { id: Date.now().toString(), text, completed: false }] })), // 动作:切换 Todo 完成状态 toggleTodo: (id) => set((state) => ({ todos: state.todos.map(todo => todo.id === id ? { ...todo, completed: !todo.completed } : todo ) })), // 动作:删除 Todo deleteTodo: (id) => set((state) => ({ todos: state.todos.filter(todo => todo.id !== id) })), })); export default useTodoStore; -
组件中使用:
jsximport useTodoStore from './store/todoStore'; const TodoList = () => { // 从 store 中获取状态和动作 const todos = useTodoStore(state => state.todos); const addTodo = useTodoStore(state => state.addTodo); const toggleTodo = useTodoStore(state => state.toggleTodo); return ( <View> <TodoInput onAddTodo={addTodo} /> <FlatList data={todos} renderItem={({ item }) => ( <TouchableOpacity onPress={() => toggleTodo(item.id)}> <Text style={item.completed ? styles.completedText : styles.todoText}> {item.text} </Text> </TouchableOpacity> )} keyExtractor={item => item.id} /> </View> ); };
2.4 原生交互设计(JS 与原生通信)
RN 不能直接访问原生 API(如相机、定位),需通过「原生模块」实现 JS 与原生的通信。
2.4.1 通信原理(旧架构 vs 新架构)
- 旧架构 :通过 Bridge 实现异步通信,流程:
- JS 侧调用原生模块方法(如
Camera.takePhoto()); - Bridge 将方法名、参数序列化为 JSON;
- 原生侧解析 JSON,执行对应方法;
- 原生侧将结果序列化后通过 Bridge 返回 JS 侧。
- JS 侧调用原生模块方法(如
- 新架构 :通过 JSI 实现同步通信,流程:
- 原生模块通过 Codegen 生成 C++ 绑定;
- JS 侧通过 JSI 直接调用 C++ 方法,无需序列化;
- 原生方法执行后直接返回结果给 JS 侧(支持同步/异步)。

2.4.2 第三方原生模块使用(以相机为例)
使用社区成熟的原生模块 react-native-camera,无需手动编写原生代码:
-
安装:
bashnpm install react-native-camera@4.x -
配置权限(iOS/Android):
-
iOS:打开
ios/MyRNProject/Info.plist,添加:xml<key>NSCameraUsageDescription</key> <string>需要相机权限拍摄照片</string> -
Android:打开
android/app/src/main/AndroidManifest.xml,添加:xml<uses-permission android:name="android.permission.CAMERA" />
-
-
组件中使用:
jsximport React, { useRef } from 'react'; import { View, TouchableOpacity, Text, StyleSheet } from 'react-native'; import { RNCamera } from 'react-native-camera'; const CameraScreen = () => { const cameraRef = useRef(null); // 拍照函数 const takePicture = async () => { if (cameraRef.current) { const options = { quality: 0.5, base64: true }; const data = await cameraRef.current.takePictureAsync(options); console.log('照片路径:', data.uri); } }; return ( <View style={styles.container}> <RNCamera ref={cameraRef} style={styles.preview} type={RNCamera.Constants.Type.back} // 后置摄像头 flashMode={RNCamera.Constants.FlashMode.off} androidCameraPermissionOptions={{ title: '相机权限', message: '需要相机权限', buttonPositive: '允许', buttonNegative: '拒绝', }} /> <TouchableOpacity style={styles.captureButton} onPress={takePicture}> <Text style={styles.buttonText}>拍照</Text> </TouchableOpacity> </View> ); }; const styles = StyleSheet.create({ container: { flex: 1, }, preview: { flex: 1, }, captureButton: { position: 'absolute', bottom: 32, left: '50%', transform: [{ translateX: -50% }], backgroundColor: 'white', width: 60, height: 60, borderRadius: 30, justifyContent: 'center', alignItems: 'center', }, buttonText: { fontSize: 16, color: '#333', }, }); export default CameraScreen;
第三部分:底层原理(深入内核,成为专家)
3.1 RN 渲染流程(从 JSX 到原生视图)
以「点击按钮更新文本」为例,拆解 RN 完整渲染流程(新架构):
步骤 1:JS 侧状态更新
jsx
const [count, setCount] = useState(0);
// 点击按钮触发状态更新
<TouchableOpacity onPress={() => setCount(count + 1)} />
- 调用
setCount后,React 标记组件为「需要重新渲染」。
步骤 2:React 构建虚拟 DOM 并 Diff
- React 执行组件函数,生成新的虚拟 DOM(Fiber 树);
- 通过 Diff 算法对比新旧 Fiber 树,得到「更新补丁(Update Queue)」。
步骤 3:JSI 同步传递更新到原生侧
- 新架构中,React 通过 JSI 直接调用 Fabric(UI 渲染层)的 C++ 方法,传递更新补丁;
- 无需序列化/反序列化(旧架构的 Bridge 瓶颈),同步执行。
步骤 4:Fabric 生成原生视图指令
- Fabric 接收更新补丁,将其转换为原生视图操作(如「创建 Text 组件」「更新 Text 内容」);
- 调用原生平台的 UI 框架(iOS 的 UIKit、Android 的 Jetpack Compose)。
步骤 5:原生侧渲染视图
- 原生侧执行 UI 操作,更新屏幕上的视图;
- 由于是同步更新,支持 React 18 的「并发渲染」(如 Suspense、useTransition)。
流程图总结:
状态变化 → React Diff → 生成 Update Queue → JSI 传递 → Fabric 处理 → 原生 UI 渲染
3.2 Hermes 引擎(RN 性能核心)
Hermes 是 Meta 推出的「轻量级 JavaScript 引擎」,专为 RN 优化,RN 0.70+ 已默认启用。

3.2.1 Hermes 核心优势
- 预编译字节码:将 JS 代码编译为字节码(.hbc 文件),减少启动时的解析时间;
- 更小的内存占用:比 V8 引擎内存占用低 30%+,适合移动设备;
- 垃圾回收优化:采用分代垃圾回收(GC),减少卡顿;
- 支持 ES6+ 特性:完全兼容 React 18 语法。
3.2.2 启用 Hermes(RN 0.74+ 默认启用)
- iOS:
ios/Podfile中默认包含use_react_native!(hermes_enabled: true); - Android:
android/gradle.properties中默认hermesEnabled=true。
3.2.3 字节码编译(生产环境)
打包时自动编译字节码,无需手动操作:
bash
# Android 打包
cd android && ./gradlew assembleRelease
# iOS 打包
通过 Xcode 归档(Archive)生成 IPA 文件
3.3 新架构核心:JSI、Fabric、TurboModules
3.3.1 JSI(JavaScript Interface)
JSI 是 JS 引擎与原生代码的「直接接口」,替代旧架构的 Bridge,核心作用:
- 允许 JS 直接调用原生 C++ 函数(无需序列化);
- 允许原生代码持有 JS 函数引用(回调更高效);
- 是 Fabric 和 TurboModules 的基础。
3.3.2 Fabric(UI 渲染层)
Fabric 是新的 UI 管理系统,替代旧架构的 UIManager,核心改进:
- 同步渲染:JS 侧更新可同步传递到原生侧,避免 Bridge 异步延迟;
- 并发渲染支持 :配合 React 18 的
useTransitionSuspense,实现非阻塞渲染; - 增量更新:只更新变化的原生视图,减少重绘。
3.3.3 TurboModules(原生模块系统)
TurboModules 替代旧架构的 NativeModules,核心优势:
- 类型安全:通过 Codegen 生成类型定义,避免参数类型错误;
- 同步调用:支持 JS 同步调用原生方法(如获取设备信息);
- 懒加载:原生模块按需加载,减少 App 启动时间。
3.3.4 Codegen 代码生成
Codegen 是新架构的「胶水工具」,作用:
- 读取 JS 侧的组件/模块定义(如
TurboModule接口); - 自动生成 C++ 中间代码,连接 JS 侧和原生侧;
- 支持多平台(iOS/Android),减少原生代码编写量。
3.4 性能优化底层逻辑
3.4.1 启动优化
- Hermes 字节码预编译:减少 JS 解析时间;
- 懒加载组件/模块 :使用
React.lazy+Suspense延迟加载非首屏组件; - 原生模块懒加载:TurboModules 自动支持,无需额外配置;
- 资源优化:压缩图片、减少首屏 JS 体积(Tree Shaking)。
3.4.2 渲染优化
- 减少重渲染 :
React.memouseMemouseCallback避免不必要的渲染; - 长列表优化 :
FlatList懒加载 +getItemLayout预计算布局; - 避免大列表一次性渲染:分页加载数据,限制每页数据量;
- 使用原生动画 :
Animated库(基于原生动画 API),避免 JS 线程阻塞。
3.4.3 内存优化
- 图片优化 :使用
react-native-fast-image缓存图片,避免重复加载; - 避免内存泄漏:清理定时器、事件订阅、监听器(useEffect 清理函数);
- 大文件处理:分段加载大文件,避免一次性加载到内存;
- Hermes 垃圾回收:启用 Hermes 的分代 GC,减少内存占用。
第四部分:实战部署与进阶(学以致用)
4.1 网络请求(Axios + 拦截器)
RN 支持 fetch API 和 axios,推荐使用 axios(拦截器、取消请求等功能更完善)。
-
安装:
bashnpm install axios -
封装请求工具(
utils/request.js):jsximport axios from 'axios'; // 创建 axios 实例 const service = axios.create({ baseURL: 'https://api.example.com', // 接口基础地址 timeout: 5000, // 超时时间 }); // 请求拦截器:添加 Token service.interceptors.request.use( (config) => { const token = 'user-token-from-storage'; // 从本地存储获取 Token if (token) { config.headers.Authorization = `Bearer ${token}`; } return config; }, (error) => Promise.reject(error) ); // 响应拦截器:统一处理结果 service.interceptors.response.use( (response) => { const res = response.data; if (res.code !== 200) { // 错误提示(可使用 react-native-toast-message) console.error('请求失败:', res.message); return Promise.reject(res); } return res.data; }, (error) => { console.error('网络错误:', error.message); return Promise.reject(error); } ); export default service; -
接口调用(
api/todo.js):jsximport request from '../utils/request'; // 获取 Todo 列表 export const getTodoList = () => { return request({ url: '/todos', method: 'GET', }); }; // 添加 Todo export const addTodo = (text) => { return request({ url: '/todos', method: 'POST', data: { text }, }); };
4.2 本地存储(AsyncStorage + Realm)
4.2.1 AsyncStorage(轻量级存储)
RN 内置的本地存储库,适合存储少量数据(如 Token、用户配置):
jsx
import AsyncStorage from '@react-native-async-storage/async-storage';
// 存储数据
const storeData = async (key, value) => {
try {
const jsonValue = JSON.stringify(value);
await AsyncStorage.setItem(key, jsonValue);
} catch (e) {
console.error('存储失败:', e);
}
};
// 获取数据
const getData = async (key) => {
try {
const jsonValue = await AsyncStorage.getItem(key);
return jsonValue != null ? JSON.parse(jsonValue) : null;
} catch (e) {
console.error('获取失败:', e);
}
};
// 示例:存储用户 Token
storeData('userToken', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...');
4.2.2 Realm(重量级存储)
Realm 是「移动数据库」,适合存储大量结构化数据(如 Todo 列表、聊天记录):
-
安装:
bashnpm install realm@12.x -
定义模型并使用:
jsximport Realm from 'realm'; // 定义 Todo 模型 const TodoSchema = { name: 'Todo', primaryKey: 'id', properties: { id: 'string', text: 'string', completed: 'bool', createTime: 'date', }, }; // 打开数据库 const openRealm = async () => { const realm = await Realm.open({ path: 'TodoDatabase', schema: [TodoSchema], }); return realm; }; // 添加 Todo 到数据库 const addTodoToRealm = async (text) => { const realm = await openRealm(); realm.write(() => { realm.create('Todo', { id: Date.now().toString(), text, completed: false, createTime: new Date(), }); }); realm.close(); }; // 查询所有 Todo const getTodosFromRealm = async () => { const realm = await openRealm(); const todos = realm.objects('Todo').sorted('createTime', true); return JSON.parse(JSON.stringify(todos)); // 转换为 JS 对象 };
4.3 打包与部署(生产环境)
4.3.1 Android 打包(生成 APK/AAB)
-
生成签名文件(仅第一次需要):
bashkeytool -genkeypair -v -keystore my-release-key.keystore -alias my-key-alias -keyalg RSA -keysize 2048 -validity 10000- 将生成的
my-release-key.keystore复制到android/app/目录。
- 将生成的
-
配置签名信息(
android/gradle.properties):propertiesMYAPP_RELEASE_STORE_FILE=my-release-key.keystore MYAPP_RELEASE_KEY_ALIAS=my-key-alias MYAPP_RELEASE_STORE_PASSWORD=你的密钥库密码 MYAPP_RELEASE_KEY_PASSWORD=你的密钥密码 -
配置
android/app/build.gradle:gradleandroid { ... defaultConfig { ... } signingConfigs { release { if (project.hasProperty('MYAPP_RELEASE_STORE_FILE')) { storeFile file(MYAPP_RELEASE_STORE_FILE) storePassword MYAPP_RELEASE_STORE_PASSWORD keyAlias MYAPP_RELEASE_KEY_ALIAS keyPassword MYAPP_RELEASE_KEY_PASSWORD } } } buildTypes { release { ... signingConfig signingConfigs.release } } } -
生成 AAB(Google Play 推荐格式):
bashcd android && ./gradlew bundleRelease- 输出路径:
android/app/build/outputs/bundle/release/app-release.aab
- 输出路径:
4.3.2 iOS 打包(生成 IPA)
-
配置开发者账号:
- 打开
ios/MyRNProject.xcworkspace(Xcode); - 选择项目 → Targets → Signing & Capabilities → 登录 Apple Developer 账号。
- 打开
-
配置打包环境:
- 选择菜单栏「Product → Scheme → Edit Scheme」,将 Build Configuration 改为 Release;
- 选择模拟器或真机(推荐用真机测试)。
-
归档打包:
- 菜单栏「Product → Archive」,等待归档完成;
- 归档完成后,点击「Distribute App」,选择「App Store Connect」,按提示完成打包;
- 生成 IPA 文件,上传到 App Store Connect。
4.3.3 热更新(CodePush)
CodePush 是微软推出的热更新服务,无需上架应用商店即可更新 JS/TS 代码:
-
安装依赖:
bashnpm install react-native-code-push@8.x -
注册 CodePush 账号:
bash# 安装 CodePush CLI npm install -g appcenter-cli # 登录 App Center appcenter login # 创建 CodePush 应用(iOS/Android 各创建一个) appcenter codepush app add MyRNApp-iOS ios react-native appcenter codepush app add MyRNApp-Android android react-native -
配置项目(以 Android 为例):
-
修改
android/app/src/main/java/com/myrnproject/MainApplication.java:javaimport com.microsoft.codepush.react.CodePush; @Override protected String getJSBundleFile() { return CodePush.getJSBundleFile(); } @Override protected List<ReactPackage> getPackages() { return Arrays.<ReactPackage>asList( new MainReactPackage(), new CodePush("你的 Android 部署密钥", getApplicationContext(), BuildConfig.DEBUG) ); }
-
-
发布热更新:
bash# 发布生产环境更新 appcenter codepush release-react -a 你的账号/MyRNApp-Android -d Production
第五部分:学习路径与讲解技巧(向入门者授课)
5.1 自学/授课学习路径(8 周计划)
| 周数 | 学习内容 | 核心目标 |
|---|---|---|
| 第 1 周 | 环境搭建 + 基础组件 + Flexbox | 能编写简单 UI 页面 |
| 第 2 周 | Hooks 状态管理 + 列表渲染 | 能实现动态数据展示(如 Todo 列表) |
| 第 3 周 | 路由管理 + 页面传参 | 能实现多页面跳转 |
| 第 4 周 | 网络请求 + 本地存储 | 能与后端接口交互、存储数据 |
| 第 5 周 | 原生模块集成 + 第三方组件 | 能使用相机、地图等原生功能 |
| 第 6 周 | 状态管理(Zustand/Redux) | 能处理复杂全局状态 |
| 第 7 周 | 性能优化 + 新架构 | 理解底层原理,优化 App 性能 |
| 第 8 周 | 打包部署 + 热更新 | 能发布生产环境 App 并支持热更新 |
5.2 向入门者讲解的核心技巧
-
先易后难,拒绝堆砌概念:
- 先让入门者跑通 Hello World,感受「写 JS 代码生成 App」的成就感;
- 再逐步引入状态、路由、网络等概念,每个知识点配 1 个可运行的小示例。
-
对比网页开发,降低学习成本:
- 讲解 JSX 时,对比 HTML(View → div、Text → span);
- 讲解样式时,对比 CSS(StyleSheet → CSS 样式表、flex 布局复用网页知识)。
-
可视化底层原理:
- 用流程图讲解 RN 渲染流程(如「JSX → 虚拟 DOM → 原生视图」);
- 用动画演示 Diff 算法(如新旧虚拟 DOM 对比,高亮变化部分)。
-
实战驱动,边做边学:
- 以「Todo 列表 → 带网络请求的 Todo 列表 → 带原生相机的 Todo 列表」为线索,串联所有知识点;
- 让入门者自己动手修改代码(如修改颜色、添加功能),强化记忆。
-
常见坑提前预警:
- 强调「Text 组件必须包裹文字」「StyleSheet 无继承性」「FlatList 必须加 keyExtractor」等新手高频错误;
- 提供常见问题排查清单(如环境搭建失败、模拟器启动不了)。
结语
React Native 0.74+ 已非常成熟,新架构和 Hermes 引擎大幅提升了性能,是跨平台开发的首选方案之一。本文从「入门实战→框架设计→底层原理→部署优化」全方位覆盖,既适合自学,也适合作为授课教材。