React Native

技术栈
前端框架
mobilecross-platformreactiosandroid

概览

React Native 技术栈概览

React Native 是 Meta(Facebook)于 2015 年开源的跨平台移动应用框架。它使用 JavaScript/TypeScript + React 语法,通过桥接层(Bridge/JSI)调用原生平台组件,实现「Learn once, write anywhere」。与 Flutter 的自绘不同,React Native 渲染的是真正的原生控件。

解决什么问题

  • 同时开发 iOS + Android → 共享 70%+ 业务代码
  • 纯原生开发成本高 → Web 前端开发者可直接上手
  • 热更新 → OTA 推送 JS Bundle,绕过 App Store 审核周期
  • 原生体验需求 → 渲染原生控件,非 WebView

关键特性

  • React 语法:类组件/函数组件 + Hooks 完全可用
  • 原生控件<View> → UIView/AndroidView,<Text> → UILabel/TextView
  • 新架构(0.68+):JSI 替换 Bridge,同步调用原生方法;Fabric 渲染器;TurboModules 按需加载
  • Fast Refresh:保存代码秒级刷新,保留状态
  • Expo 生态:零配置开发环境,简化构建/发布
  • CodePush:热更新 JS 代码
  • 社区插件丰富:react-navigation、react-native-reanimated、react-native-maps

安装

环境准备

  • Node.js:>= 18 LTS
  • macOS:Xcode 15+(iOS 开发必须)
  • Windows/Linux:Android Studio + JDK 17
  • Watchman(macOS/Linux):文件监听工具

安装命令

使用 Expo(推荐新手)

npx create-expo-app@latest MyApp
cd MyApp
npx expo start

手机安装 Expo Go App,扫码即可运行。

使用 React Native CLI(灵活项目)

npx @react-native-community/cli init MyApp
cd MyApp

# iOS(仅 macOS)
cd ios &;& pod install && cd ..

# 启动
npx react-native run-ios     # iOS
npx react-native run-android # Android

环境验证

npx react-native doctor    # 诊断环境问题

常见安装问题

Q1: iOS pod install 慢或失败

用国内镜像:pod repo updatebundle exec pod install。也可用 CDN 源:删除 Podfile 中 source 行。

Q2: Android 报 SDK location not found

创建 android/local.properties,添加:

sdk.dir=/Users/xxx/Library/Android/sdk

Q3: Metro bundler 端口冲突

npx react-native start --port 8082 换端口。

Q4: Windows 下 Android 编译慢

使用 WSL2 开发,或在 android/gradle.properties 中增大堆内存:org.gradle.jvmargs=-Xmx2048m

示例

React Native 例程:Todo List——FlatList 与状态管理

目标

通过一个功能完整的 Todo List,展示 RN 核心:FlatList、TextInput、useState、StyleSheet、TouchableOpacity。

完整代码

// App.js
import React, { useState } from 'react';
import {
  View,
  Text,
  TextInput,
  TouchableOpacity,
  FlatList,
  StyleSheet,
  Alert,
} from 'react-native';

export default function App() {
  const [todos, setTodos] = useState([]);
  const [inputText, setInputText] = useState('');

  const addTodo = () => {
    if (inputText.trim() === '') return;
    setTodos([
      ...todos,
      {
        id: Date.now().toString(),
        text: inputText.trim(),
        completed: false,
      },
    ]);
    setInputText('');
  };

  const toggleTodo = (id) => {
    setTodos(
      todos.map((todo) =>
        todo.id === id ? { ...todo, completed: !todo.completed } : todo
      )
    );
  };

  const deleteTodo = (id) => {
    Alert.alert('确认', '删除这条任务?', [
      { text: '取消', style: 'cancel' },
      {
        text: '删除',
        style: 'destructive',
        onPress: () => setTodos(todos.filter((t) => t.id !== id)),
      },
    ]);
  };

  const renderItem = ({ item }) => (
    <View style={styles.todoItem}>
      <TouchableOpacity
        style={styles.checkbox}
        onPress={() => toggleTodo(item.id)}
      >
        <Text style={styles.checkText}>
          {item.completed ? '✅' : '⬜'}
        </Text>
      </TouchableOpacity>

      <Text
        style={[
          styles.todoText,
          item.completed && styles.completedText,
        ]}
      >
        {item.text}
      </Text>

      <TouchableOpacity onPress={() => deleteTodo(item.id)}>
        <Text style={styles.deleteBtn}>🗑️</Text>
      </TouchableOpacity>
    </View>
  );

  return (
    <View style={styles.container}>
      <Text style={styles.title}>📋 Todo List</Text>

      <View style={styles.inputRow}>
        <TextInput
          style={styles.input}
          placeholder="输入新任务..."
          value={inputText}
          onChangeText={setInputText}
          onSubmitEditing={addTodo}
        />
        <TouchableOpacity style={styles.addBtn} onPress={addTodo}>
          <Text style={styles.addBtnText}>+</Text>
        </TouchableOpacity>
      </View>

      <FlatList
        data={todos}
        keyExtractor={(item) => item.id}
        renderItem={renderItem}
        ListEmptyComponent={
          <Text style={styles.empty}>暂无任务,添加一个吧 ✨</Text>
        }
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: { flex: 1, paddingTop: 60, paddingHorizontal: 20, backgroundColor: '#f5f5f5' },
  title: { fontSize: 28, fontWeight: 'bold', textAlign: 'center', marginBottom: 20 },
  inputRow: { flexDirection: 'row', marginBottom: 16 },
  input: {
    flex: 1, borderWidth: 1, borderColor: '#ddd', borderRadius: 8,
    paddingHorizontal: 12, paddingVertical: 10, fontSize: 16, backgroundColor: '#fff',
  },
  addBtn: {
    marginLeft: 8, backgroundColor: '#007AFF', borderRadius: 8,
    width: 44, justifyContent: 'center', alignItems: 'center',
  },
  addBtnText: { color: '#fff', fontSize: 24, fontWeight: 'bold' },
  todoItem: {
    flexDirection: 'row', alignItems: 'center', backgroundColor: '#fff',
    padding: 14, borderRadius: 8, marginBottom: 8, elevation: 1,
  },
  checkbox: { marginRight: 10 },
  checkText: { fontSize: 22 },
  todoText: { flex: 1, fontSize: 16 },
  completedText: { textDecorationLine: 'line-through', color: '#999' },
  deleteBtn: { fontSize: 20, padding: 4 },
  empty: { textAlign: 'center', color: '#999', marginTop: 40, fontSize: 16 },
});

运行步骤

npx create-expo-app@latest TodoRN
# 将上面代码覆盖 App.js
npx expo start
# 扫码运行

预期表现

  • 输入框提交新任务
  • 点击 ⬜ → ✅ 标记完成(文字加删除线)
  • 点击 🗑️ 弹出确认后删除
  • FlatList 高效渲染长列表

教程

React Native 移动开发入门教程

第一章:架构演进——从 Bridge 到 JSI

旧架构(Bridge)

JS Thread ←→ Bridge(JSON 序列化)←→ Native Thread

每次通信都要跨越 Bridge,数据序列化为 JSON。问题:列表快速滚动时掉帧(异步 + 序列化开销)。

新架构(Fabric + TurboModules + JSI)

JS Thread ←→ JSI(直接 C++ 调用)←→ Native Thread

JSI 让 JS 同步调用原生方法(参考 C++ 虚函数表),Fabric 新渲染器支持优先级调度,TurboModules 按需加载原生模块。

第二章:核心组件速查

组件 用途 对应原生
View 容器,布局 UIView / android.view
Text 文本 UILabel / TextView
TextInput 输入框 UITextField / EditText
ScrollView 滚动容器 UIScrollView / ScrollView
FlatList 高性能列表 UITableView / RecyclerView
TouchableOpacity 触控反馈 手势识别
Image 图片 UIImageView / ImageView
Modal 模态弹窗 -

第三章:导航

React Navigation 是事实标准:

npm install @react-navigation/native @react-navigation/native-stack
npx expo install react-native-screens react-native-safe-area-context
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';

const Stack = createNativeStackNavigator();

function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator>
        <Stack.Screen name="Home" component={HomeScreen} />
        <Stack.Screen name="Detail" component={DetailScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

第四章:样式系统

React Native 使用 CSS 子集,通过 StyleSheet.create() 定义:

const styles = StyleSheet.create({
  box: {
    flex: 1,               // Flexbox 布局(默认 column)
    backgroundColor: '#fff',
    paddingHorizontal: 16,
    marginTop: 20,
  },
});

关键差异:

  • 没有 CSS 选择器、继承、级联
  • 单位是无单位数字(dp/pt)
  • flexDirection 默认 column(Web 是 row)

第五章:原生模块调用

需要调用相机、GPS 等原生能力时:

npx expo install expo-camera
import { Camera } from 'expo-camera';

const { status } = await Camera.requestCameraPermissionsAsync();

思考题

  1. React Native 的 FlatList 和 ScrollView 性能差异的根源是什么?
  2. 旧 Bridge 架构的「异步瓶颈」具体在哪?新 JSI 如何解决?
  3. RN 和 Flutter 各适合什么场景?选型依据是什么?

参考资料

暂无参考文献