最近在做 React Native 应用往鸿蒙系统迁移时,碰到一个特别有代表性的需求:主 Feed 列表,第一屏加载 20 条,滚动到底部自动拉取下一页,同时支持下拉刷新。这套逻辑在 iOS 和 Android 的 React Native 上已经是成熟方案,但迁移到鸿蒙版 React Native 后,列表组件底层桥接方式不一样了,数据请求的时序也变得更敏感,曾经“能用就行”的分页写法直接暴露出一堆问题。这篇文章把我实际踩坑和最终落地的方案完整记录下来,核心就是用 React Query 的 useInfiniteQuery 来管理无限滚动的数据流,配合 FlatList 完成 UI 层联动。
文章会覆盖几个部分:为什么鸿蒙上的无限滚动不能简单照搬老代码、工程落地前必须搞清楚的环境问题、useInfiniteQuery 的数据层设计思路、一组可以直接拿走的完整实现代码,以及我在鸿蒙真机和模拟器上实测遇到的几个坑。适合正在做 RN 鸿蒙适配、或者在调研鸿蒙开发方案的团队参考。
1. 为什么说鸿蒙上的无限滚动不是简单搬一个 FlatList
很多同学第一反应是:无限滚动不就是 FlatList 加 onEndReached 再加一个页码 state 吗?这套东西在 Android 上跑了两年都没事,换个平台怎么就不行了?实际上无限滚动的完整链路远不止 UI 层的“滚动到底部触发一次回调”,它是一条从数据获取、状态管理到 UI 渲染的闭环。
1.1 无限滚动的本质是一条数据链路
拆开来看,一次完整的无限滚动交互至少包含四个环节:
- 数据获取:根据当前页码或游标向服务端请求一页数据,同时还要知道还有没有下一页。
- 状态管理:维护加载中、加载成功、加载失败、刷新中、加载更多中、没有更多数据、空数据等一组状态。
- UI 触发:列表滚动接近底部时触发加载,下拉时触发刷新,加载更多时在底部展示 loading。
- 渲染层:把内存中累积的所有页数据扁平化后交给列表渲染,同时控制虚拟化参数避免长列表卡顿。
这四个环节在 iOS 和 Android 的 React Native 上可以靠成熟的社区方案盖住,但鸿蒙版 RN 的问题在于:FlatList 不再走原来那套 VirtualizedList 的完整实现,而是桥接到鸿蒙原生的列表容器上,网络请求语义、事件回调时机、JS 与原生侧通信的效率全都和原来不一样。任何一个环节出问题,都会表现为“滚动不到底、重复请求、数据错乱、白屏”。
1.2 鸿蒙 RN 版的问题出在“链路分层”
我在排查过程中一个很深的体会是:鸿蒙版 React Native 不是什么全新的东西,它是把 RN 的 JS 层保留,把原来的 Android/iOS 原生实现替换成鸿蒙的 ArkUI 组件和系统能力。这带来一个结果——JS 层的 API 看着和原版一样,但组件行为细节有大量差异。
举一个最典型的例子:FlatList 的 onEndReached 在 Android 上非常灵敏,滚动条只要进入阈值范围立刻触发;但在鸿蒙的某些版本上,这个回调的触发存在明显的“滞后”,如果你用手头的页码 state 去控制是否发起请求,很容易出现快速滑动时只触发一次、停下来又突然连发两次的情况。这个我在第 5 章会细讲。
还有一点,鸿蒙 RN 的网络层默认走的是鸿蒙系统的网络能力,虽然暴露出来的还是 fetch 接口,但在 TLS 握手、DNS 解析、并发连接数上的行为和标准 Android 不完全一致。如果列表分页接口本身的响应时间不稳定,前端又在每次滚动到底部时机械地加一页,最终表现就是列表停在某个位置一直转圈。
1.3 为什么少有人聊这块
说实话,鸿蒙版 RN 的中文资料目前还处在一个很尴尬的阶段:官方文档能保证你把 Hello World 跑起来,但社区里深入讲“某个业务组件在鸿蒙上的适配差异”的内容很少。原因也简单,真正把大型 RN 应用完整迁移到鸿蒙的团队本来就少,迁移完又愿意把过程中的坑写出来的更少。
所以我才决定把这次实践的完整链路写出来。项目最终其实不是“把老代码搬过来”,而是借这个机会把数据层重构了一遍,用 React Query 统一管理分页、缓存、刷新和加载更多逻辑。这样即使鸿蒙端列表组件某个版本行为有变化,需要动的也只是 UI 层的一小段代码,数据层是稳定的。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 鸿蒙 RN 工程落地前,先把这三个前置门槛踩平
如果你是从零开始搭鸿蒙 RN 工程,建议先别急着写无限滚动,把下面三件事确认好。这里每一件我都实际卡过,顺序也按照“从依赖到运行时再到打包产物”来排。
2.1 react-native-harmony 依赖安装与版本锁定
鸿蒙版 React Native 不是用 npm 上那个官方 react-native 包直接跑起来的,而是需要引入 OpenHarmony SIG 组维护的 react-native-harmony 仓库。这个仓库会提供一套鸿蒙原生工程模板,以及对应的 JS 侧补丁包。
比较稳妥的做法是:
- 先确定鸿蒙 SDK 版本(API 10 还是 API 12),再选择对应版本的 react-native-harmony 分支。
- 在工程根目录通过
ohpm安装鸿蒙原生侧依赖,而不是npm install。 - JS 侧依然通过 npm 安装 @react-native-community/cli 等常
