从 React 无痛过渡到 React Native

2 阅读4分钟

如果你会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 的呢?

image.png

1.1 你可以放心带过来的

React(Web)里你会的在 RN 里
函数组件、useState / useEffect / useMemo一样用
组件组合、受控/非受控思路一样用
TypeScript、类型约束一样用
把样式对象化、StyleSheet 类似 CSS-in-JS 的思路很像,只是属性名用驼峰

1.2 需要刻意切换的几件事

  1. 没有 div / p / span:用 <View> 做容器,<Text> 包一切可见文字
  2. 没有浏览器默认样式:布局默认是 Flex,单位是数字(逻辑像素),没有 px
  3. 长列表:别养成 map 一万个节点的好习惯,用 FlatList(类似「虚拟列表」)
  4. 多页:没有 URL 栏,用 react-navigation(栈 / Tab)表达「去哪一页」
  5. 调试:开发时靠 Metro 给设备喂 JS;真机常用 adb

1.3 运行时三条线(对应 Web 里的「构建 + 浏览器」)

  1. Metro:开发时 npm start,给设备提供 JS bundle,可简单理解成「专门服务 RN 的打包」
  2. 你的代码AppAppRegistry 注册——相当于「挂载根组件」,只是入口 API 名字不同
  3. 原生工程:Android / iOS 工程负责安装、权限、图标;不必第一天全啃完,但要知卡顿时该看 JS 还是原生

二、从「浏览器刷新」到「设备拉包」:环境与 adb

adb:真机调试时的「数据线协议」

在 Web 开发中访问 localhost:xxx;而在 RN 中,真机往往要连 本机 Metroadb reverse tcp:8081 tcp:8081 是常用的“一键桥”。

场景命令
看设备adb devices
无线调试(不稳定,甚至部分厂商会阉割此功能)adb connect 10.10.20.4:2222
断开无线adb disconnect 10.10.20.4:2222
重启 adbadb kill-serveradb start-server
Metro 端口映射adb reverse tcp:8081 tcp:8081
shell / 传文件adb shelladb push / adb pull

三、移动端 UI 分层:把「页面结构」从浏览器搬到屏幕中

在 Web 中常会将网页分为3大部分:顶栏、内容区、底栏。RN 没有语义化 HTML,但分层思路完全可复用

层级RN 里常见做法
状态栏StatusBar
标题区View + Text 或导航 header
内容区ScrollView / FlatList
底部多入口react-navigationTab

四、组件与样式:Web 习惯 → RN 写法

4.1 标签对照

  • divView(里面别直接写纯文本)。
  • 文字一律 → Text
  • imgImage(网络图注意 Android INTERNET 权限)。
  • 大列表 → FlatList,少用 ScrollView 塞几千个子节点。

4.2 样式:仍是「声明式 + 对象」,只是没有 CSS 文件

默认 FlexStyleSheet.create 集中管理,和 CSS-in-JS 的写法很接近。

五、导航:把「路由」从浏览器迁到 App 内

Web 里可能是 React Router + URL;RN 里用 react-navigation 表达「栈」「Tab」:

  • NavigationContainer:包住整棵导航树(类似 Router 顶层)
  • Bottom Tabs:底部模块
  • Native Stack:详情压栈、侧滑返回
  • react-native-screensreact-native-gesture-handler:和原生手势、性能配合

注意:Tab 里的页面要跳到 外层 Stack 的详情页,类型上常用 Composite Navigation


六、来个实战练练手(android为例):

image.png

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.xmlbuild.gradle权限、包名、签名
资源strings.xml、图标应用名、上架
桥接NativeModule调原生 SDK

Android / iOS 语言不必先精通;先建立「JS 解决不了就上原生层」的分工意识就好啦。

结语

无痛过渡的本质:继续用 React 组织逻辑,把「标签与运行环境」换成 RN 那一套;导航替代 URL,FlatList 替代map,Metro + 设备 替代「浏览器热更新」,其实很容易就上手啦!