跳到主要内容

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/ObjCC++ 共享
并发模式不支持支持 React 18 Concurrent
TypeSafetyJSON编译时类型检查

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 引擎:

对比JavaScriptCoreHermes
编译JITAOT(提前编译为字节码)
启动时间较慢快 50%+
内存占用较高低 30%+
包体积较大较小
调试Safari DevToolsChrome 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 引擎,核心优势:

  1. AOT 编译:构建时将 JS 编译为字节码,启动时间减少 50%+
  2. 内存占用低:优化了 GC(分代收集),内存减少 30%+
  3. 包体积小:字节码比 JS 源码更紧凑
  4. 中低端设备友好:不依赖 JIT,启动快

Q3: React Native 如何做性能优化?

答案

渲染层面:

  • FlatList 替代 ScrollView,设置 windowSizegetItemLayout
  • React.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 NativeFlutter
语言JavaScript/TypeScriptDart
渲染映射到原生组件自绘引擎(Skia)
UI 一致性平台原生风格跨平台像素级一致
热重载Fast RefreshHot Reload
生态npm 生态丰富pub.dev 相对小
Web 支持react-native-webFlutter 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+ 特有逻辑
}

相关链接