ReactNative快速入门
ReactNative是Facebook推出的跨平台移动应用开发框架,结合了Web开发的灵活性和原生应用的性能优势。根据2024年StackOverflow开发者调查,ReactNative在全球移动开发框架使用率中排名第二,其核心优势包括:
- 代码复用率高达85%以上(iOS/Android)
- 热重载(Hot Reloading)开发体验
- 庞大的生态系统
- 渐进式学习曲线
架构
React Native团队一直在重新设计React Native的核心内部,以使开发人员能够创建更高质量的体验
📌 在旧版本(0.68前)ReactNative使用的是旧版架构:
- JavaScript层:业务逻辑与组件定义
- 桥接层(Bridge):异步通信通道、数据交换等等
- 原生层:调用平台特定API、UI布局及渲染
这种架构使得JS线程和UI线程分离,保证了界面流畅性,但也带来了特定的性能优化挑战,如:JSBridge异步通信、数据转换开销、启动时加载所有原生模块、无法内存共享等等问题
📌 在0.68版本后ReactNative使用新版架构对以上问题做了优化:
- JavaScript层:业务逻辑与组件定义
- 原生层:调用平台特定API、UI布局及渲染
- JSI:JS与原生内存共享、变量可直接调用,降低数据序列化成本
- Fabric:与原生同步通信、共享内存、提高UI渲染效率
- TurboModule:提高启动速度、按需加载必要模块
点击这里了解更多 架构相关文档
JSX
使用JSX
开发现代Web组件是React开发者必备知识,在ReactNative中同样的和React一样,如果你还不清楚如何使用JSX
、TSX
,建议先去学习 React 的官方文档基础知识
// 组件声明
const App = () => {
return (
<View style={{ background: 'red' }}>
<Text>Hello ReactNative</Text>
</View>
);
};
2
3
4
5
6
7
8
当然,如果你已经是个合格(优秀)的React开发者,那么ReactNative的上手也将会畅通无阻
内置组件
React Native提供了许多内置的 核心组件 供你在应用程序中使用。组件的使用非常简单,类似于web的使用一些控件元素等等,因为都是些React JSX所以语法或者使用上基本上是没有任何差别的
小贴士
本篇不做组件的详细介绍,只是对一些组件和web做简单的对比,读者阅读后应该也就明白了
基础组件
基础组件就是很常见的组件,大多数应用程序最终都会使用这些基本组件中的一个或多个
- View组件:类似于web中的div,不过它直接就是个弹性盒子flex
- Text组件:承接文字的容器,类似web中的p
- Image组件:类似于web的image标签,用于显示图片,功能更强大点。需要显示设置宽高,否则不会有web的默认行为(自动撑开)
- TextInput:类似于web的input标签,用于内容的录入等等
import { View, Text, Image, TextInput } from 'react-native';
function Page() {
const [text, onChangeText] = React.useState('Useless Text');
return <>
<View style={{ justifyContent: 'center' }}>
<Text>Hello, React Native</Text>
<Image
style={styles.tinyLogo}
source={require('@/assets/img/logo.png')}
/>
<TextInput
onChangeText={onChangeText}
value={text}
/>
</View>
</>
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
用户控件
一些常用的用户交互的组件,如:Button
、Switch
等等
import { Button, Switch } from 'react-native';
function Page() {
const [isEnabled, setIsEnabled] = useState(false);
const toggleSwitch = () => setIsEnabled(previousState => !previousState);
function onSubmit() {}
return <>
<Button
onPress={onSubmit}
title="Submit"
color="#841584"
/>
<Switch
trackColor={{false: '#767577', true: '#81b0ff'}}
thumbColor={isEnabled ? '#f5dd4b' : '#f4f3f4'}
ios_backgroundColor="#3e3e3e"
onValueChange={toggleSwitch}
value={isEnabled}
/>
</>
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
很简单,基本看一遍就可以上手
列表组件
和web不太一样,在App中滚动容器需要主动声明一个容器元素是可以滚动的或者使用提供的列表元素
ReactNative提供了通用的ScrollView
元素,以及FlatList
、SectionList
、VirtualLizedList
等滚动元素。除了ScrollView,其余类似于web中使用的虚拟滚动,对于庞大数据性能更有优势
import { ScrollView } from 'react-native';
function Page() {
return <ScrollView style={{ flex: 1 }}>
一段可以滚动的容器,我是文本内容...
</ScrollView>
}
2
3
4
5
6
7
8
读者可以试试FlatList
、SectionList
,很简单
一般来说,对于简单的滚动元素(一次性的内容)采用ScrollView
,对于大数据来说就需要使用其他了
其他
除此之外ReactNative还提供了其他很多便捷的组件,如:Alert
、Modal
、StatusBar
等等,感兴趣的可以直接前往 官方其他组件文档 ,比较简单就不多做介绍了
第三方组件
你并不局限于React Native捆绑的组件和api。React Native拥有一个由数千名开发人员组成的社区。如果您正在寻找具有特定功能的库,官方内置组件满足不了你,可以通过以下渠道寻找合适的组件:
比如这里使用 Expo Image Picker 本地设备图片选取插件,搜索当前插件打开对应的文档,直接安装
➜ npx expo install expo-image-picker
然后其他相关操作步骤及注意事项,文档中都会提及直接按照对应的流程执行就行。如这里需要申请设备一些权限等等
样式
使用React Native,你可以使用JavaScript来设计你的应用程序。所有的核心组件都接受一个名为style的对象。样式名称和值通常与CSS在web上的工作方式相匹配,除了名称使用驼色大小写,例如:backgroundColor
而不是backgroundColor
样式可以是一个普通的JavaScript对象。这就是我们通常使用的示例代码。你也可以传递一个样式数组——数组中的最后一个样式具有优先级,所以你可以使用它来继承样式
随着组件复杂性的增长,使用样式表通常更简洁。创建在一个地方定义多个样式。这里有一个例子
import React from 'react';
import {StyleSheet, Text, View} from 'react-native';
const Page = () => {
return (
<View style={styles.container}>
<Text style={styles.red}>just red</Text>
<Text style={styles.bigBlue}>just bigBlue</Text>
<Text style={[styles.bigBlue, styles.red]}>bigBlue, then red</Text>
<Text style={[styles.red, styles.bigBlue]}>red, then bigBlue</Text>
</View>
);
};
const styles = StyleSheet.create({
container: {
marginTop: 50,
},
bigBlue: {
color: 'blue',
fontWeight: 'bold',
fontSize: 30,
},
red: {
color: 'red',
},
});
export default Page;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
如果你熟悉TailWind,那么 NativeWind 将是一个不错的选择
平台特定代码
有时候RN并不能通过同一套代码实现不同平台的逻辑(兼容问题),或者说某个业务针对不同的平台有不同的实现逻辑,这时候就需要针对不同平台提供逻辑了
ReactNative 提供了Platform
API来判断当前设备的平台
import { Platform } from 'react-native';
Platform.OS === 'ios' ? true : false
2
3
正如以上可以通过Platform.OS
在逻辑处通过if/else
编写不同平台的专属逻辑
除此之外,可以通过平台文件名扩展区分不同平台
# IOS平台
user-page.ios.tsx
# Android平台
user-page.android.tsx
# web平台
user-page.tsx
2
3
4
5
6
如果读者用过其它的跨端/跨平台应用程序,如:uniapp、taro等等,应该对这个很熟悉,还有上方的平台条件代码,在uniapp中也是可以使用平台条件注释
// #ifdef MP-WEIXIN
import a from 'a/wx'
// #endif
// #ifndef H5
import a from 'a/index'
// #endif
2
3
4
5
6
7
路由
以上知识已经足够可以开发App了,而路由是丰富App功能的核心。就像一个网站一样不会只有一个网页,不同的地址导航对应着不同的网页内容,App中也需要通过不同的路由切换不同的App屏幕显示
官方提供了 React Navigation 核心库来支撑这一功能
➜ npm install @react-navigation/native @react-navigation/native-stack @react-navigation/elements
路由注册
假设这里有一个页面Home.tsx
:
import { View, Text } from 'react-native';
export default function HomePage() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
</View>
);
}
2
3
4
5
6
7
8
9
然后在根元素中注册路由App.tsx
:
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
const Stack = createNativeStackNavigator();
export default function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Home" component={HomePage} />
</Stack.Navigator>
</NavigationContainer>
);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
那么页面就会显示Home组件内容

路由导航
当有多个路由页面时如何进行路由切换呢?首先,我们再创建一个页面Detail.tsx
,然后进行路由注册
现在,在Home页面执行导航
import { useNavigation } from '@react-navigation/native';
export default function HomePage() {
const navigation = useNavigation();
return <>
<Button onPress={() => navigation.navigate('Detail')}>
Go to Details
</Button>
</>
}
2
3
4
5
6
7
8
9
10
11
对没错,它提供了useNavigation
钩子函数来执行一些导航功能,上面就使用了navigate
通过传入目标路由的名字,就可以正常跳转了
除此之外,还有很多其他的功能函数,如:push
、back
、pop
、传参等等,读者感兴趣可直接参考文档
其他
ReactNative Navigation是一个强大的导航库,使用它你可以做到很多功能
- 导航栏设置,如标题、背景等等
- 开箱即用的Tab栏导航
- 嵌套导航、Deeplink等
- Modal、Drawer等等场景功能导航
💡如何页面鉴权? 鉴权在RN中与React web应用设计类似,可以通过全局数据状态标识用户的登录态及信息,可以在根组件中拿到状态,如果没有权限直接登录就可以
// 伪代码
export default RouterGuard({ children }) {
const { isLogin } = useUserStore();
// 可通过状态再此做手脚
if (!isLogin) return <Stack.Screen name="Page" component={LoginPage} />
return <>
<Stack.Screen name="Home" component={HomeScreen} />
{/* 其他页面... */}
</>
}
// 注册
export default function App() {
return <AuthProvider>
<Stack.Navigator>
<RouterGuard />
</Stack.Navigator>
</AuthProvider>
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
与React类似不多做介绍
Expo
Expo 是ReactNative官方推荐的一个框架,类似于React框架 Next、Vue框架 Nuxt 一样,这些框架通过一些约定,使得应用开发更加的简单。如基于文件的导航系统、主题系统等等
使用Expo开发RN应用非常简单,上文中所有的内容在Expo中都是可以共同使用的,而Expo也提供了一些替代方案。除此之外,还有很多强大的功能
你可以直接上手Expo
➜ npx create-expo-app@latest --template
创建项目时可以选择使用的模板,如:ts、空模板、导航模板等等
推荐ReactNative开发直接使用Expo
持久化
在移动应用开发中,数据持久化指将应用程序数据存储在设备本地存储介质中,保证应用关闭后数据不丢失,ReactNative提供了多种持久化方式
这里简单介绍几种常用的方式:AsyncStorage、Image Cache、FileSystem
AsyncStorage
AsyncStorage适用一些简单的结构化数据,类似于web中的localstorage
➜ npm install react-native-storage
➜ npm install @react-native-async-storage/async-storage
2
初始化:
// storage.js
import Storage from 'react-native-storage';
import AsyncStorage from '@react-native-async-storage/async-storage';
const storage = new Storage({
// 最大容量,默认值1000条数据循环存储
size: 1000,
// 存储引擎:对于RN使用AsyncStorage,对于web使用window.localStorage
// 如果不指定则数据只会保存在内存中,重启后即丢失
storageBackend: AsyncStorage,
// 数据过期时间,默认一整天(1000 * 3600 * 24 毫秒),设为null则永不过期
defaultExpires: 1000 * 3600 * 24,
// 读写时在内存中缓存数据。默认启用。
enableCache: true,
// 你可以在构造函数这里就写好sync的方法
// 或是在任何时候,直接对storage.sync进行赋值修改
// 或是写到另一个文件里,这里require引入
// 如果storage中没有相应数据,或数据已过期,
// 则会调用相应的sync方法,无缝返回最新数据。
sync: require('你可以另外写一个文件专门处理sync'),
});
export default storage;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
增删改查:
// 新增、修改
storage.save({
key: 'loginState',
data: {
from: 'some other site',
userid: 'some userid',
token: 'some token',
},
expires: 1000 * 3600,
});
// 查询
storage
.load({
key: 'loginState',
autoSync: true,
syncInBackground: true,
})
.then(ret => /* */)
.catch(err => /* */);
// 删除
storage.remove({
key: 'lastPage',
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Image Cache
通常App中的很多图片都会做缓存,以便断网情况下还可以看到相应的图片内容。expo-image可以很方便的完成这些工作
import { Image } from 'expo-image';
export default function App() {
return <>
<Image
source={{
uri: "https://picsum.photos/seed/696/3000/2000",
cacheKey: "xxx"
}}
/>
</>
}
2
3
4
5
6
7
8
9
10
11
12
FileSystem
Expo-file-system提供对存储在设备本地的文件系统的访问。它还能够从网络url上传和下载文件
➜ npx expo install expo-file-system
此工具库的功能非常强大,这里简单的介绍几种使用方式,其他可以具体看文档:
import * as FileSystem from 'expo-file-system';
// 下载文件
FileSystem.downloadAsync(uri)
// 获取文件信息
FileSystem.getInfoAsync(uri)
// 删除文件
FileSystem.deleteAsync(uri)
// 上传
FileSystem.uploadAsync(url, fileUri, options)
2
3
4
5
6
7
8
9
10
这是上传参数解释:
Parameter | Type | Description |
---|---|---|
url | string | 上传服务器地址 |
fileUri | string | 本地设备文件地址 |
options(optional) | FileSystemUploadOptions | 可选参数 |
此工具库的功能相对来说还是很强大的
第一个RN应用
React Native开发App就是这么简单,对于React骨灰级玩家基本上过一遍文档就可以开干了😂
目前ReactNative开发推荐直接使用Expo,初始化一个项目:
➜ npx create-expo-app@latest
# 或者初始模板
➜ npx create-expo-app@latest --template
2
3
初始化后的项目结构大概长这个样子:
➜ App-Structure
├── app # 存放所有页面
│ ├── (tabs) # tab导航页面
│ │ ├── _layout.tsx # (tabs)路由
│ │ ├── explore.tsx
│ │ └── index.tsx
│ ├── +not-found.tsx # 默认404页面布局
│ └── _layout.tsx # App根路由
├── app.json # App相关配置信息
├── assets # 静态文件
├── components # 组件
├── constants # 常量
├── eslint.config.js
├── hooks
├── package.json
├── pnpm-lock.yaml
├── scripts # 项目一些脚本
└── tsconfig.json
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
直接在Terminal运行项目:
➜ npm run start
运行后终端会提示各种运行命令,根据命令直接操作即可,比如:按i
运行ios程序、a
运行Android程序
打开手机扫描终端二维码可以直接在移动设备上跑项目,前提是移动设备上也安装了Expo
客户端
📌 Expo如何安装? Expo客户端本身直接在应用市场找到即可安装,SDK通常需要一些魔法才行
- 对于Android用户使用魔法比较简单,这里就不用介绍了
- IOS用户如果移动设备上难以使用魔法,如何Mac/Windows上可以用的话,可开启电脑系统代理,然后iPhone代理到电脑IP就可以施展魔法了
打包发布
这里使用Expo开发的直接推荐使用EAS
EAS Build允许您为Google Play商店或Apple App Store构建应用程序二进制文件,或者直接构建到模拟器或者自己的设备中
由文章于篇幅原因,关于构建发布可阅读后续文章