📚 全栈开发学习系列
阶段一:编程基础 ✅ 已完成
01-08 路线总览 → Python → C 语言 → 数据结构 → Git → Linux 命令行
阶段二:Web 全栈 ✅ 已完成
09-16 HTML/CSS/JS → HTTP → FastAPI → PostgreSQL → 认证授权 → 博客实战
阶段三:前端深化 ✅ 已完成
17-25 React → TypeScript → Next.js → Tailwind → 工程化 → 测试 → 状态管理
阶段四:跨平台 App
26 跨平台开发:React Native 与 Expo(当前篇)
27 React Native 进阶:导航与状态管理
28 React Native 网络请求与设备能力
29 React Native 实战:构建完整移动应用
阶段五至六共 6 篇,后续持续更新

跨平台开发:React Native 与 Expo

阶段四第一篇 · 难度:入门
读完本篇你将能:理解 React Native 的跨平台原理与新架构,用 Expo 脚手架在 5 分钟内创建可运行的移动应用,掌握核心组件(View/Text/Pressable 等)与 StyleSheet 样式系统,用 Expo Router 实现页面跳转,并在真机或模拟器上预览自己的第一个 App。
📑 本文目录
01React Native 是什么:从 Bridge 到新架构
02Expo 框架入门:为什么选 Expo
03环境搭建:5 分钟跑起第一个 App
04创建第一个应用:项目结构解析
05核心组件:View、Text、Pressable
06样式系统:StyleSheet 与 Flexbox
07导航与路由:Expo Router 文件路由
08常见错误与最佳实践

React Native 是什么:从 Bridge 到新架构

前三个阶段你一直在 Web 领域打转——HTML/CSS/JS、React、Next.js,所有代码最终跑在浏览器里。现在,你要把同样的 React 知识搬进手机。React Native 就是这座桥。

React Native 是 Meta(原 Facebook)在 2015 年开源的跨平台移动开发框架。你用 JavaScript 和 React 语法写代码,它把你写的 <View>、<Text> 渲染成 Android 的 android.view.View 和 iOS 的 UIView——真正的原生 UI 组件,不是嵌套网页。

打个比方:WebView 方案像在手机屏幕上贴一张网页的打印照片,看起来像但摸起来不对——没有原生滚动惯性、没有原生手势、长按弹不出系统菜单。React Native 则像一位双语建筑师,你用 React 的设计图纸(JSX),他用 Android 的砖块(Kotlin/Compose)和 iOS 的砖块(Swift/UIKit)实打实地砌出一栋原生的房子。

架构演进:从 Bridge 到新架构

React Native 的核心架构在 2024 年完成了从"Bridge 时代"到"新架构时代"的切换。理解这个演进,你才能明白为什么 0.87 版本敢说自己是"生态级变革"。

维度 旧架构(Bridge) 新架构(Fabric + TurboModules)
通信方式 异步 JSON 消息队列 同步 JSI 直接调用
渲染管线 三层异步(Shadow Tree → Yoga → Native) 单层同步(C++ Shadow Tree 直接提交)
原生模块 NativeModules(初始化时全量加载) TurboModules(按需懒加载)
Bridge 回退 支持 legacy interop 0.85 起彻底移除,无回退

JSI(JavaScript Interface)是新架构的基石。旧架构中,JS 和原生之间靠一个异步消息队列通信,每次调用都要序列化/反序列化 JSON 数据。JSI 则允许 JavaScript 直接持有 C++ 对象的引用,调用原生方法就像调用普通 JS 函数一样同步——没有中间层,没有序列化开销。

React Native 0.85(2026 年 4 月发布)是第一个完全基于新架构的稳定版,彻底移除了 Bridge 回退层。到 0.87(2026 年 8 月发布),新架构已经成熟,带来了 Strict TypeScript API、Metro 0.87 和实验性 Swift Package Manager 支持。

💡 小贴士
React Native 0.87 要求 Node.js 22+、Android Gradle Plugin 9、Kotlin 2.0+。如果你已有旧项目升级,先运行 npx @react-native-community/cli@latest doctor 检查环境兼容性。

Expo 框架入门:为什么选 Expo

你已经理解了 React Native 的跨平台原理。但如果直接用裸 React Native(Bare Workflow),光配 iOS 的 CocoaPods 和 Android 的 Gradle 就能卡住新手一整天。Expo 就是为了消除这个痛点而生的。

Expo 是建立在 React Native 之上的完整开发平台。你可以把它类比为 React 生态中的 Vite + Vercel:本地提供脚手架和开发服务器,云端提供构建打包和热更新服务。一行命令创建项目,手机扫二维码就能预览,不用打开 Xcode 或 Android Studio。

能力 Bare React Native Expo
项目创建 手动配 Xcode + Android Studio 一行 npx create-expo-app
真机预览 编译 IPA/APK 再安装 Expo Go 扫码秒开
原生模块 手动 link + pod install expo install 自动兼容
打包发布 本地或自建 CI 编译 EAS Build 云端一键打包
热更新 自建 CodePush 服务 EAS Update 原生集成

Expo 生态核心组件

Expo 不只是一个脚手架,它是一整套工具链。你需要记住以下几个核心概念:

• Expo Go:手机上的预览 App。开发时扫码即可在真机上看到最新代码效果,无需编译安装。适合纯 JS 逻辑的开发阶段。
• Expo SDK:一套版本化的 npm 包集合。SDK 57(2026 年 6 月发布)对应 React Native 0.86,包含 expo-router、expo-image、expo-secure-store 等几十个官方模块。
• Expo Router:基于文件的路由系统,类似 Next.js 的 App Router。在 app/ 目录下创建文件即自动注册为路由。
• EAS(Expo Application Services):云端构建和提交服务。eas build 在云端编译 IPA/APK,eas submit 直接提交到 App Store / Google Play。

Expo SDK 57 于 2026 年 6 月 30 日发布,搭载 React Native 0.86,带来了 Expo UI 生产就绪、更快的原生构建速度、以及 expo prebuild 默认启用等特性。SDK 58 正在 canary 阶段开发中,将支持 React Native 0.87。

💡 小贴士
Expo Go 有一个限制:它只包含 SDK 预编译的原生模块。如果你需要自定义原生代码(如第三方蓝牙 SDK),需要使用 npx expo prebuild 生成原生项目,或用 Development Build 替代 Expo Go。

环境搭建:5 分钟跑起第一个 App

理论够了,动手。以下在 macOS 上演示完整流程(唯一能同时编译 Android 和 iOS 的平台)。Termux 用户注意:React Native 开发需要 Xcode 和 Android Studio,Termux 无法参与本阶段。

Step 1:安装 Node.js 22+

React Native 0.87 要求 Node.js 22 以上版本。用 nvm 管理版本最方便:

Terminal
nvm install 22
nvm use 22
node -v
# v22.14.0

Step 2:创建 Expo 项目

不需要全局安装任何 CLI,用 npx 直接运行:

Terminal
npx create-expo-app@latest my-app
# 选择默认模板 (blank with tabs)
# 等待 npm install 完成约 30-60 秒
cd my-app
npx expo start

终端会显示一个二维码和开发服务器菜单。此时你有三种方式预览 App:

📱 Expo Go 扫码

手机装 Expo Go App,扫终端二维码秒开。最快但限制最多。

🍎 iOS 模拟器

终端按 i 启动。需先装 Xcode(App Store 免费)。

🤖 Android 模拟器

终端按 a 启动。需先装 Android Studio。

Step 3:安装 iOS / Android 工具链(可选)

如果只用 Expo Go 预览,可以跳过本步。但要编译发布原生包,必须安装完整工具链:

1 iOS:从 App Store 安装 Xcode(约 12GB),然后运行 sudo xcode-select --install 安装 Command Line Tools
2 Android:从官网下载 Android Studio,通过 SDK Manager 安装 Android SDK 35+ 和 Platform Tools
3 在 Android Studio → Virtual Device Manager 中创建一个模拟器(推荐 Pixel 7 + API 35)
⚠️ 常见错误
直接运行 npx react-native init — 这是旧版裸 RN 命令,2026 年已不推荐。Expo 项目用 npx create-expo-app 创建。
✓ 正确:始终用 npx create-expo-app@latest,它自动配置好 Expo Router、TypeScript 和新架构。

创建第一个应用:项目结构解析

你已经用 create-expo-app 创建了项目。现在来理解每个文件的作用——这跟你在阶段三熟悉的 Next.js 结构很像,但有关键区别。

项目目录结构

my-app/
1
2
3
4
5
6
7
8
9
my-app/
├── app/         # Expo Router 路由目录
│  ├── _layout.tsx  # 根布局
│  ├── index.tsx    # 首页 /
│  └── about.tsx    # /about 页
├── app.json      # Expo 配置(图标/名称/版本)
├── package.json    # 依赖与脚本
├── tsconfig.json    # TypeScript 配置
└── app.config.ts # 动态配置(可选)

跟 Next.js 一样,app/ 目录下的文件自动映射为路由。_layout.tsx 是根布局组件,所有页面都在它内部渲染。index.tsx 对应根路径 /,about.tsx 对应 /about。

入口文件:app/index.tsx

这是 create-expo-app 默认生成的首页。你看到了熟悉的 React 语法,但组件名不再是 div / span:

app/index.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { Text, View } from 'react-native'
import { StyleSheet } from 'react-native'
export default function HomeScreen() {
  return (
    <View style={styles.container}>
      <Text>Hello, React Native!</Text>
    </View>
  )
}
const styles = StyleSheet.create({
  container: { flex: 1, alignItems: 'center', justifyContent: 'center' }
})

看到区别了吗?Web 里你写 <div> 和 <span>,这里变成了 <View> 和 <Text>。样式也从 className + CSS 文件变成了 StyleSheet.create + 内联 style 对象。

💡 小贴士
React Native 没有 div、span、img 等任何 HTML 标签。所有文本必须放在 <Text> 组件内——裸写文本会报错。<View> 相当于 div,但默认使用 flex 布局(flexDirection 默认 column)。

核心组件:View、Text、Pressable

你已经看到了 View 和 Text。React Native 的组件库远不止这两个——以下是你在 90% 场景中会用到的核心组件。

Web HTML RN 组件 用途
<div> <View> 容器、布局
<span>/<p> <Text> 文本显示
<button> <Pressable> 可点击区域
<img> <Image> 图片
<input> <TextInput> 文本输入框
overflow:auto <ScrollView> 滚动容器
<ul>/<li> <FlatList> 高性能长列表

Pressable:交互的核心

Web 里你用 onClick 处理点击。React Native 用 Pressable 组件,它比旧的 TouchableOpacity 更灵活,能感知按下/抬起/移入/移出等完整触摸生命周期。

app/components/Counter.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import { useState } from 'react'
import { Pressable, Text, View } from 'react-native'
export default function Counter() {
  const [count, setCount] = useState(0)
  return (
    <View style={{ alignItems: 'center', marginTop: 50 }}>
      <Text>Count: {count}</Text>
      <Pressable
        onPress={() => setCount(c + 1)}
        style={({ pressed }) => [{
          backgroundColor: pressed ? '#6d28d9' : '#8b5cf6',
          padding: 12, borderRadius: 8
        }]}
      >
        <Text style={{ color: '#fff' }}>+1</Text>
      </Pressable>
    </View>
  )
}

关键变化:onClick 变成了 onPress,style 支持函数形式,通过 pressed 参数感知按压状态实现视觉反馈——这是原生应用体验的关键。

FlatList:长列表的标配

如果用 ScrollView 渲染 1000 条数据,所有行都会一次性创建——内存爆炸。FlatList 采用虚拟化(virtualization),只渲染屏幕可见区域 + 少量缓冲区的行,滚动时动态回收复用。

app/components/TaskList.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import { FlatList, Text, View } from 'react-native'
const tasks = [
  { id: '1', title: '学习 RN' },
  { id: '2', title: '写练习' },
  // ...100 条
]
<FlatList
  data={tasks}
  keyExtractor={(item) => item.id}
  renderItem={({ item }) => (
    <Text>{item.title}</Text>
  )}
/>

样式系统:StyleSheet 与 Flexbox

你在阶段三已经熟练使用 Tailwind 和 CSS 写样式了。React Native 的样式系统跟 Web CSS 有 80% 相似,但那 20% 的差异会让你频繁踩坑。

StyleSheet.create 而非 CSS 文件

React Native 不用 CSS 文件,所有样式通过 JavaScript 对象定义。StyleSheet.create 会将样式对象注册为引用 ID,避免每次渲染创建新对象,同时提供属性名校验(写错属性名会在开发时报警告)。

Web CSS React Native
margin-top: 16px; marginTop: 16
background-color: #fff backgroundColor: '#fff'
font-size: 14px fontSize: 14
className 引用样式表 style 属性内联传对象
单位 px / rem / % 纯数字(代表 dp/pt)

Flexbox:默认方向是 column

这是 Web 开发者转 RN 最容易踩的坑:Web 的 display:flex 默认 flexDirection: row(水平排列),而 React Native 默认 flexDirection: column(垂直排列)。

要水平排列子元素,必须显式设置 flexDirection: 'row'。

app/components/Row.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
const styles = StyleSheet.create({
  row: {
    // 水平排列,子元素左右间距相等
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
    padding: 16,
  },
  box: {
    flex: 1,  // 占据可用空间
    height: 60,
    backgroundColor: '#8b5cf6',
  }
})
⚠️ 常见错误
在 Text 上写 fontSize 然后期待内层 span 继承 — React Native 的样式不继承!只有 <Text> 内嵌套的 <Text> 会继承父 Text 的文字样式,<View> 之间不继承任何样式。
✓ 正确:每个需要样式的组件都必须显式传入 style 属性。

导航与路由:Expo Router 文件路由

你在阶段三已经用 Next.js 的 App Router 体验过文件路由。Expo Router 几乎完全一致——目录即路由,文件即页面。这让 Web 开发者转 RN 几乎零学习成本。

文件到路由的映射规则

文件路径 路由 URL
app/index.tsx /(首页)
app/about.tsx /about
app/(tabs)/home.tsx /home(分组不出现在 URL)
app/post/[id].tsx /post/42(动态路由)

页面跳转:router.push

跟 Next.js 的 useRouter 一样,Expo Router 提供 useRouter 和 useLocalSearchParams 钩子:

app/index.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { router, Link } from 'expo-router'
import { Pressable, Text, View } from 'react-native'
export default function Home() {
  return (
    <View>
      <Pressable onPress={() => router.push('/about')}>
        <Text>跳转到 About</Text>
      </Pressable>
      {/* 声明式写法 */}
      <Link href="/post/42" asChild>
        <Pressable><Text>查看文章 #42</Text></Pressable>
      </Link>
    </View>
  )
}

两种跳转方式:命令式用 router.push(),声明式用 <Link> 组件。asChild 属性让 Link 把导航行为委托给子组件,保持你的自定义样式。

💡 小贴士
在 app/post/[id].tsx 中读取参数:const { id } = useLocalSearchParams()。这跟 Next.js 的 useParams 完全一致。

常见错误与最佳实践

初学 React Native 最容易踩的坑几乎都来自「Web 思维惯性」。下面列出的四个错误覆盖了 80% 的新手问题。

⚠️ 常见错误
直接在 View 里写文字 — React Native 中所有文本必须包裹在 <Text> 组件内。在 <View> 中直接写裸文字会报错。
✓ 正确:<View><Text>Hello</Text></View>
⚠️ 常见错误
用 display:block / display:inline 控制布局 — React Native 默认是 Flexbox 布局,display 属性只支持 flex 和 none,不支持 block / inline / grid。
✓ 正确:用 flexDirection、alignItems、justifyContent 控制排列。
⚠️ 常见错误
忽略 SafeArea,内容被刘海/状态栏遮挡 — iOS 灵动岛和 Android 状态栏会遮挡顶部内容。
✓ 正确:使用 react-native-safe-area-context 的 SafeAreaView 包裹根布局,Expo Router 默认已内置。
⚠️ 常见错误
用 <div> 和 <span> 写组件 — RN 没有 HTML 标签,div → View,span / p → Text,button → Pressable。
✓ 正确:从 react-native 导入核心组件,不使用任何 HTML 标签。
✅ 最佳实践速查
1. 用 StyleSheet.create 而非内联对象 — RN 会将其优化为引用比较,避免每次渲染创建新对象
2. 列表用 FlatList 而非 ScrollView + map — FlatList 虚拟化长列表,只渲染可见区域
3. 图片用 require() 加载本地资源 — source={require('./img.png')} 而非 source={uri}
4. 平台判断:Platform.OS === 'ios' 或 Platform.select() 做平台分支

动手练习

从易到难三个梯度,建议按顺序完成。每个练习的代码在本地 Expo Go 中即时预览效果。

Level 1 基础:计数器增强
在 Counter 组件基础上添加:减 1 按钮(count 不能小于 0)、重置按钮、显示当前数值的颜色(0 灰色、1-9 绿色、10+ 橙色)。
提示:用 Math.max(0, count - 1) 防止负数
Level 2 进阶:多页面导航应用
创建三个页面:首页(展示文章列表)、文章详情页(动态路由 /post/[id])、关于页。用 FlatList 渲染列表,点击跳转详情页,详情页用 useLocalSearchParams 读取 id 并显示对应内容。
提示:准备一个 posts 数组,按 id 查找内容
Level 3 挑战:Todo List 应用
构建一个完整的待办应用:TextInput 输入新任务,FlatList 展示列表,每项可标记完成 / 删除,顶部显示统计(已完成 / 总数)。使用 useState 管理状态,用 StyleSheet.create 定义样式,添加 Platform.OS 判断让 iOS 和 Android 有不同的输入框圆角。
提示:数据结构 type Todo = { id: number; text: string; done: boolean }

知识回顾

用下面这些关键词自测掌握程度,每个标签对应一个核心概念:

React Native Expo SDK Fabric 新架构 JSI Expo Go EAS Build create-expo-app View / Text / Pressable FlatList StyleSheet.create Flexbox 布局 Expo Router 文件路由 动态路由 [id] SafeAreaView Platform.OS
📖 下一篇预告
下一篇《React Native 进阶:导航与状态管理》将深入 Expo Router 的 Tab 导航、Stack 导航、Drawer 侧边栏,并引入 Zustand 在移动端做状态管理——把你在阶段三学到的 Web 状态管理思路迁移到移动端。还会介绍 AsyncStorage 本地持久化和 React Native 的手势交互基础。
系列进度:26/35 · 阶段四进行中