如果你会React,那RN真的没有那么难,Hooks、props/state——这些在React中怎么写,在RN中就怎么写,本文将带你从 React 无痛过渡到 React Native!
一起来看张图
flowchart LR
A[熟悉的 React 组件逻辑] --> B[Metro 打包]
B --> C[RN 运行时]
C --> D[原生 View 绘制]
D --> E[手机屏幕]
F[react-navigation] --> C
G[View / Text / FlatList] --> D
从React到RN,变化主要集中在:没有 DOM、用原生组件替代 div/span、用导航替代浏览器地址栏,以及多了一个 Metro + 真机调试 的环节。 其实,Metro 的角色可粗略类比为开发时的打包服务。
一、React 是怎么映射到 RN 的呢?
1.1 你可以放心带过来的
| React(Web)里你会的 | 在 RN 里 |
|---|---|
函数组件、useState / useEffect / useMemo … | 一样用 |
| 组件组合、受控/非受控思路 | 一样用 |
| TypeScript、类型约束 | 一样用 |
把样式对象化、StyleSheet 类似 CSS-in-JS 的思路 | 很像,只是属性名用驼峰 |
1.2 需要刻意切换的几件事
- 没有
div/p/span:用<View>做容器,<Text>包一切可见文字 - 没有浏览器默认样式:布局默认是 Flex,单位是数字(逻辑像素),没有
px - 长列表:别养成
map一万个节点的好习惯,用FlatList(类似「虚拟列表」) - 多页:没有 URL 栏,用
react-navigation(栈 / Tab)表达「去哪一页」 - 调试:开发时靠 Metro 给设备喂 JS;真机常用 adb
1.3 运行时三条线(对应 Web 里的「构建 + 浏览器」)
- Metro:开发时
npm start,给设备提供 JS bundle,可简单理解成「专门服务 RN 的打包」 - 你的代码:
App用AppRegistry注册——相当于「挂载根组件」,只是入口 API 名字不同 - 原生工程:Android / iOS 工程负责安装、权限、图标;不必第一天全啃完,但要知卡顿时该看 JS 还是原生
二、从「浏览器刷新」到「设备拉包」:环境与 adb
adb:真机调试时的「数据线协议」
在 Web 开发中访问 localhost:xxx;而在 RN 中,真机往往要连 本机 Metro,adb reverse tcp:8081 tcp:8081 是常用的“一键桥”。
| 场景 | 命令 |
|---|---|
| 看设备 | adb devices |
| 无线调试(不稳定,甚至部分厂商会阉割此功能) | adb connect 10.10.20.4:2222 |
| 断开无线 | adb disconnect 10.10.20.4:2222 |
| 重启 adb | adb kill-server → adb start-server |
| Metro 端口映射 | adb reverse tcp:8081 tcp:8081 |
| shell / 传文件 | adb shell;adb push / adb pull |
三、移动端 UI 分层:把「页面结构」从浏览器搬到屏幕中
在 Web 中常会将网页分为3大部分:顶栏、内容区、底栏。RN 没有语义化 HTML,但分层思路完全可复用:
| 层级 | RN 里常见做法 |
|---|---|
| 状态栏 | StatusBar |
| 标题区 | View + Text 或导航 header |
| 内容区 | ScrollView / FlatList |
| 底部多入口 | react-navigation 的 Tab |
四、组件与样式:Web 习惯 → RN 写法
4.1 标签对照
div→View(里面别直接写纯文本)。- 文字一律 →
Text。 img→Image(网络图注意 Android INTERNET 权限)。- 大列表 →
FlatList,少用ScrollView塞几千个子节点。
4.2 样式:仍是「声明式 + 对象」,只是没有 CSS 文件
默认 Flex,StyleSheet.create 集中管理,和 CSS-in-JS 的写法很接近。
五、导航:把「路由」从浏览器迁到 App 内
Web 里可能是 React Router + URL;RN 里用 react-navigation 表达「栈」「Tab」:
NavigationContainer:包住整棵导航树(类似 Router 顶层)- Bottom Tabs:底部模块
- Native Stack:详情压栈、侧滑返回
react-native-screens、react-native-gesture-handler:和原生手势、性能配合
注意:Tab 里的页面要跳到 外层 Stack 的详情页,类型上常用 Composite Navigation。
六、来个实战练练手(android为例):
6.1 入口:手势要在最前面
react-navigation 约定:第一行 import 'react-native-gesture-handler'(Web 里没有这步)。
// index.js
import 'react-native-gesture-handler';
import { AppRegistry } from 'react-native';
import App from './App';
// ...
AppRegistry.registerComponent(appName, () => App);
6.2 根组件:类似Provider 套娃,是不是很熟悉?
// App.tsx
return (
<GestureHandlerRootView style={styles.sySyRoot}>
<SafeAreaProvider>
<StatusBar /* … */ />
<SyRootNav />
</SafeAreaProvider>
</GestureHandlerRootView>
);
6.3 类型:路由表(类似定义 Route 的 params)
export type SyFeedItem = {
id: string;
title: string;
likes: string;
};
export type SyTabParamList = { SyTabHome: undefined; /* … */ };
export type SyRootStackParamList = {
SyMainTabs: undefined;
SyPostDetail: { item: SyFeedItem };
};
6.4 导航:Stack + Tab(两层路由)
<NavigationContainer theme={sySyNavTheme}>
<SyStack.Navigator>
<SyStack.Screen name="SyMainTabs" component={SySyMainTabs} />
<SyStack.Screen name="SyPostDetail" component={SySyPostDetail} />
</SyStack.Navigator>
</NavigationContainer>
6.5 首页:组合导航 + FlatList
type SyNav = CompositeNavigationProp</* Tab + Stack */>;
const navigation = useNavigation<SyNav>();
<FlatList
data={data}
numColumns={2}
renderItem={({ item }) => (
<Pressable onPress={() => navigation.navigate('SyPostDetail', { item })}>
{/* … */}
</Pressable>
)}
/>
七、何时需要动原生工程?(React 开发者的新边界)
| 类别 | 典型文件 | 常见原因 |
|---|---|---|
| 配置 | AndroidManifest.xml、build.gradle | 权限、包名、签名 |
| 资源 | strings.xml、图标 | 应用名、上架 |
| 桥接 | NativeModule 等 | 调原生 SDK |
Android / iOS 语言不必先精通;先建立「JS 解决不了就上原生层」的分工意识就好啦。
结语
无痛过渡的本质:继续用 React 组织逻辑,把「标签与运行环境」换成 RN 那一套;导航替代 URL,FlatList 替代map,Metro + 设备 替代「浏览器热更新」,其实很容易就上手啦!