React Native 基础与原理
问题
React Native 的架构原理是什么?新架构(New Architecture)做了哪些改进?
答案
1. React Native 是什么
React Native 是 Meta 开源的跨端移动应用框架,允许使用 React 和 JavaScript/TypeScript 构建 iOS 和 Android 原生应用。核心理念是 "Learn Once, Write Anywhere" —— 不追求一套代码跑所有平台,而是用相同的开发范式开发各平台应用。
2. 旧架构(Bridge Architecture)
旧架构的核心是 Bridge(桥接层),JS 和 Native 通过异步 JSON 消息通信:
问题:
- 性能瓶颈:所有通信都需 JSON 序列化/反序列化
- 异步限制:无法同步调用 Native 方法
- 单一线程桥:高频通信时容易拥塞(如滚动、动画)
- 启动慢:需要加载完整 JS Bundle 后才能渲染
3. 新架构(New Architecture)
React Native 0.68+ 引入的新架构,包含四个核心改进:
3.1 JSI(JavaScript Interface)
JSI 取代了 Bridge,允许 JS 直接调用 C++ 对象,实现 同步通信:
// 旧架构:通过 Bridge 异步通信
NativeModules.MyModule.doSomething(arg); // 异步,需序列化
// 新架构:通过 JSI 直接调用
// JS 可以直接持有 C++ HostObject 的引用
const result = global.__myModule.doSomething(arg); // 同步,无序列化
3.2 Fabric(新渲染器)
Fabric 是新的 UI 渲染系统,支持同步渲染和并发特性:
| 对比 | 旧架构 | Fabric |
|---|---|---|
| 渲染线程 | 异步队列 | 可同步渲染 |
| Shadow 树 | Java/ObjC | C++ 共享 |
| 并发模式 | 不支持 | 支持 React 18 Concurrent |
| TypeSafety | JSON | 编译时类型检查 |
3.3 TurboModules
惰性加载的原生模块系统,替代旧的 NativeModules:
// turbo-module 定义(codegen 生成类型安全的接口)
import type { TurboModule } from 'react-native';
import { TurboModuleRegistry } from 'react-native';
export interface Spec extends TurboModule {
multiply(a: number, b: number): number; // 同步方法
getConstants(): { PI: number };
}
export default TurboModuleRegistry.getEnforcing<Spec>('Calculator');
优势:
- 懒加载:用到时才初始化,加速启动
- 类型安全:Codegen 生成 C++/Java/ObjC 接口代码
- 同步调用:通过 JSI 直接调用 Native 方法
3.4 Codegen
编译时代码生成工具,根据 TypeScript 类型定义自动生成原生接口代码:
// JS 侧定义接口
import type { TurboModule } from 'react-native';
export interface Spec extends TurboModule {
getUserId(): Promise<string>;
setTheme(theme: 'light' | 'dark'): void;
}
// Codegen 自动生成 → C++ 接口 → Java/ObjC 桥接代码
4. Hermes 引擎
Hermes 是 Meta 专为 React Native 优化的 JS 引擎:
| 对比 | JavaScriptCore | Hermes |
|---|---|---|
| 编译 | JIT | AOT(提前编译为字节码) |
| 启动时间 | 较慢 | 快 50%+ |
| 内存占用 | 较高 | 低 30%+ |
| 包体积 | 较大 | 较小 |
| 调试 | Safari DevTools | Chrome DevTools / Flipper |
// 检查是否使用 Hermes
const isHermes = (): boolean => {
return !!(global as any).HermesInternal;
};
5. 样式与布局
React Native 使用 Yoga 布局引擎,基于 Flexbox:
import { StyleSheet, View, Text } from 'react-native';
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'column', // 默认 column(Web 默认 row)
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#fff',
},
title: {
fontSize: 24,
fontWeight: 'bold',
// 注意:RN 不支持 CSS 简写
// ❌ margin: '10px 20px'
// ✅ 需要分开写
marginTop: 10,
marginHorizontal: 20,
},
});
function App(): React.ReactElement {
return (
<View style={styles.container}>
<Text style={styles.title}>Hello RN</Text>
</View>
);
}
Flexbox 差异
React Native 的 Flexbox 和 Web 的有几处不同:
flexDirection默认column(Web 默认row)- 不支持
gap的旧版本需要用margin替代 - 尺寸单位无
px/rem/%,数字即 dp(密度无关像素) - 不支持 CSS 简写(如
margin: 10px 20px)
6. 导航方案
// React Navigation — 最主流方案
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
type RootStackParamList = {
Home: undefined;
Detail: { id: string };
};
const Stack = createNativeStackNavigator<RootStackParamList>();
function App(): React.ReactElement {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Detail" component={DetailScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
7. 性能优化要点
import React, { useCallback, useMemo } from 'react';
import { FlatList, Image } from 'react-native';
// 1. 使用 FlatList 替代 ScrollView(大列表)
function OptimizedList({ data }: { data: Item[] }): React.ReactElement {
const renderItem = useCallback(({ item }: { item: Item }) => (
<ListItem item={item} />
), []);
const keyExtractor = useCallback((item: Item) => item.id, []);
return (
<FlatList
data={data}
renderItem={renderItem}
keyExtractor={keyExtractor}
// 2. 控制渲染窗口
windowSize={5}
maxToRenderPerBatch={10}
// 3. 移除屏幕外视图
removeClippedSubviews={true}
// 4. 预计算 item 高度
getItemLayout={(_, index) => ({
length: ITEM_HEIGHT,
offset: ITEM_HEIGHT * index,
index,
})}
/>
);
}
// 5. 使用 React.memo 避免不必要的重渲染
const ListItem = React.memo(({ item }: { item: Item }) => (
<View>
{/* 6. 图片使用 FastImage 库优化缓存 */}
<Image source={{ uri: item.avatar }} style={styles.avatar} />
<Text>{item.name}</Text>
</View>
));
性能优化清单
- 使用
FlatList/SectionList,避免ScrollView渲染大数据 - 用
useCallback/useMemo减少渲染 - 图片使用
react-native-fast-image库 - 复杂动画使用
react-native-reanimated(在 UI 线程执行) - 使用 Flipper 进行性能分析
- 启用 Hermes 引擎
8. 与原生通信
// Native Module(TurboModule 方式)
import { NativeModules, NativeEventEmitter } from 'react-native';
// 调用原生方法
const { CameraModule } = NativeModules;
async function takePhoto(): Promise<string> {
const uri = await CameraModule.capture({
quality: 0.8,
facing: 'back',
});
return uri;
}
// 监听原生事件
const emitter = new NativeEventEmitter(CameraModule);
const subscription = emitter.addListener('onPhotoTaken', (event) => {
console.log('Photo URI:', event.uri);
});
// 记得清理
subscription.remove();
常见面试问题
Q1: React Native 新架构和旧架构的核心区别是什么?
答案:
| 维度 | 旧架构 | 新架构 |
|---|---|---|
| 通信方式 | Bridge(异步 JSON) | JSI(同步 C++ 绑定) |
| 渲染器 | 旧渲染器 | Fabric(C++ Shadow Tree) |
| 原生模块 | NativeModules(启动全加载) | TurboModules(懒加载) |
| 类型安全 | 运行时 | Codegen 编译时检查 |
| React 并发 | 不支持 | 支持 Concurrent Mode |
核心是用 JSI 替代 Bridge,消除了 JSON 序列化开销,实现了 JS 与 Native 的同步直接调用。
Q2: Hermes 引擎相比 JavaScriptCore 有什么优势?
答案:
Hermes 是 Meta 为 RN 定制的 JS 引擎,核心优势:
- AOT 编译:构建时将 JS 编译为字节码,启动时间减少 50%+
- 内存占用低:优化了 GC(分代收集),内存减少 30%+
- 包体积小:字节码比 JS 源码更紧凑
- 中低端设备友好:不依赖 JIT,启动快
Q3: React Native 如何做性能优化?
答案:
渲染层面:
FlatList替代ScrollView,设置windowSize、getItemLayoutReact.memo阻止不必要重渲染- 避免 inline style 创建新对象
动画层面:
- 使用
react-native-reanimated(UI 线程执行动画) useAnimatedStyle避免 JS 线程阻塞
包体积:
- 启用 Hermes
- Code Splitting(使用
React.lazy+ Metro bundler) - 图片压缩、使用 WebP 格式
启动优化:
- Hermes AOT 字节码
- TurboModules 懒加载
- 减少
AppRegistry初始化依赖
Q4: React Native 和 Flutter 的核心区别?
答案:
| 维度 | React Native | Flutter |
|---|---|---|
| 语言 | JavaScript/TypeScript | Dart |
| 渲染 | 映射到原生组件 | 自绘引擎(Skia) |
| UI 一致性 | 平台原生风格 | 跨平台像素级一致 |
| 热重载 | Fast Refresh | Hot Reload |
| 生态 | npm 生态丰富 | pub.dev 相对小 |
| Web 支持 | react-native-web | Flutter Web |
| 学习曲线 | React 开发者友好 | 需学习 Dart |
| 性能 | 新架构接近原生 | 接近原生 |
选择建议:
- 团队有 React 经验 → React Native
- 追求 UI 一致性和自定义 → Flutter
- 需要大量原生交互 → React Native(生态更丰富)
Q5: React Native 中如何处理平台差异代码?
答案:
import { Platform, StyleSheet } from 'react-native';
// 方式 1:Platform.OS 条件判断
const instructions = Platform.OS === 'ios'
? 'Press Cmd+R to reload'
: 'Double tap R to reload';
// 方式 2:Platform.select
const styles = StyleSheet.create({
container: {
...Platform.select({
ios: { paddingTop: 44 },
android: { paddingTop: 24 },
default: { paddingTop: 0 },
}),
},
});
// 方式 3:平台特定文件
// Button.ios.tsx
// Button.android.tsx
// 导入时自动选择:import Button from './Button';
// 方式 4:Platform.Version 判断系统版本
if (Platform.OS === 'android' && Platform.Version >= 33) {
// Android 13+ 特有逻辑
}