资讯动态

RN for OpenHarmony实战:收藏列表开发与性能优化指南

发布时间:2026/9/20 13:08:57 来源:尧图企业网站定制
1. 项目背景与需求确认1.1 为什么是RN for OpenHarmony以及为什么先做收藏列表如果你正在关注跨端框架在国产系统上的落地React Native for OpenHarmony以下简称RNOH这个名字应该不陌生。这个项目是OpenHarmony生态里把RN运行时搬到ArkUI上的一次重要尝试目标是让现存的RN代码库不用大改就能跑在鸿蒙设备上。但说实话RNOH目前还处在快速迭代期很多能力并不像在Android/iOS上那么成熟。正因如此选一个“看起来简单但实际链路完整”的功能来做技术验证是很聪明的做法。收藏列表就是一个典型的例子它需要网络请求、本地持久化、列表渲染、交互反馈、状态同步几乎覆盖了一个业务模块的所有基础能力但又不涉及太多复杂业务逻辑非常适合作为RNOH适配的第一个切入点。我在实际项目里就是这么干的。当时团队接到一个“鸿蒙适配”的预研任务时间紧、没有真机适配经验如果直接上手做全量业务迁移风险会非常大。后来我们挑了一个用户等级高、使用频次也不低的收藏功能把它作为RNOH的第一个落地模块。这个模块跑通了后面再迁其他模块就有了底气。还有一个现实原因收藏列表的UI结构相对规整列表项复杂度可控。它不像首页那样有各种各样的banner、弹窗、悬浮球也不像IM那样有长连接和消息推送。一个列表页加一个点击交互这刚好可以验证RNOH在“列表渲染、触摸事件、异步存储”这三块基础能力上的表现。1.2 功能边界定义越清晰越好动手写代码之前先把“收藏列表”这个需求拆干净。我们当时定义的功能边界是这样的收藏列表的数据来源有三部分本地已缓存的数据、接口拉取的最新数据、用户操作后的增量变更。列表项展示封面图、标题、作者、收藏时间、收藏状态。点击收藏按钮取消收藏点击整个列表项进入内容详情。下拉刷新、上拉加载更多这是列表页的标配。无网络时允许查看已缓存数据但取消收藏操作要给出离线提醒。这份需求拆解看着简单但它实际上决定了后面所有技术方案的选择。比如说如果不需要离线浏览那本地缓存就可以不做那么重如果需要实时同步收藏状态那就要考虑用一个全局状态管理而不是每个页面自己维护一个状态。所以在动手之前我建议你把需求边界写清楚特别是数据一致性、离线策略、异常反馈这几个点它们会直接影响技术选型。2. 技术方案选型与架构设计2.1 RNOH环境下技术栈怎么选RNOH虽然目标是兼容RN但它底层跑的是ArkUI的渲染引擎所以在技术选型上不能完全照搬Android/iOS那套经验。我梳理一下我们最终确定的方案表你可以直接参考能力模块选型方案选型原因列表组件FlatListRN内置RNOH对FlatList做了适配长列表性能优于ScrollView map支持虚拟化状态管理Zustand轻量级收藏状态需要跨页面同步但全局Store用Redux太重Zustand心智负担低本地缓存AsyncStorageRNOH适配版RNOH社区已提供支持API与RN一致适合存JSON结构数据网络请求axios与RN保持一致拦截器机制方便统一处理token和错误码图片加载RN内置Image 内存缓存列表封面图缓存策略比Android/iOS更敏感稍后展开说日期格式化day.js体积小工期紧不自己封装时间处理这套方案的核心逻辑是复用RN生态里最成熟的库不为了“RNOH专属适配”而引入太多没验证过的新东西。RNOH本身就还在成长期你要是再叠一堆实验性库出了问题你根本分不清是框架的锅还是库的锅。2.2 为什么选Zustand而不是Redux Toolkit收藏状态的跨页面同步是个刚需。比如用户从收藏列表进入详情页在详情页里取消了收藏返回列表页时列表里的状态必须同步更新。如果用组件局部state就得层层回调或者用事件总线维护起来很痛苦。Redux Toolkit确实更“正统”但考虑到收藏这个业务域的全局状态只有“收藏集合”这一个数据源用Redux等于杀鸡用牛刀——要写action、reducer、slice还要手动配置store心智负担不小。Zustand的思路更直接定义一个store hook任意组件都能读写还支持选择器订阅性能上也不差。代码量对比一下就能看出差别Redux Toolkit版本需要创建slice文件、配置store、包裹Provider、useSelector useDispatch配合使用。Zustand只需要创建一个hook直接调用更新方法即可而且点击收藏按钮、取消收藏、判断是否已收藏所有这些都能在一个store里搞定。实际在RNOH上跑下来Zustand的更新频率很低只更新收藏状态不会触发整个列表重渲染性能表现完全够用。我在项目里用了一个小技巧列表项组件里订阅收藏状态时用一个selector返回boolean值只有该值变化时才会触发重渲染。这样即使收藏列表很长点击某个按钮也不会导致整个列表刷一遍。2.3 本地缓存层不要小看AsyncStorage的速度差异收藏列表这种功能离线可看是很有价值的。用户在弱网或飞行模式下打开收藏列表能正常看到内容体验会好很多。所以本地缓存不是可选项而是必选。RNOH的AsyncStorage适配包用起来和标准RN几乎一样但一个关键差异体现在“启动读取速度”上。我自己实测下来在低端设备上读取大量JSON数据时AsyncStorage的初始化耗时比Android的MMKV要明显高一些。所以这里有一个实操建议收藏数据要分层存储不要把全量数据一次性塞进一个key里。我会把收藏数据拆成三层列表摘要层存收藏列表的简要信息id、标题、封面缩略图、收藏时间用于列表页快速渲染。详情缓存层存收藏内容的完整信息用户进入详情页时优先读这个。状态标记层只存一份“收藏id集合”的索引用于快速判断某个内容是否已收藏。这个分层的核心思路是“用空间换启动时间”。列表页首屏只需要摘要层的数据不需要把详情都加载进来。等用户下拉刷新或者点击进入详情再按需读取。3. 数据模型与全局状态设计3.1 收藏数据的数据结构设计收藏列表的数据结构看着简单但设计不好后面会踩坑。我直接贴一个我们实际在用的结构你照着抄基本不会出错interface CollectItem { id: string; // 内容唯一ID type: article | video | audio; // 内容类型 title: string; // 标题 coverUrl: string; // 封面图URL authorName: string; // 作者 authorAvatar: string; // 作者头像 summary: string; // 摘要 collectedAt: number; // 收藏时间戳 detailUrl: string; // 详情页地址 extraMap: Recordstring, any; // 扩展字段备用 }有几个设计细节值得说。第一id必须用字符串类型不要用number。因为很多后端的ID是雪花ID或哈希ID超出JavaScript安全整数范围后number类型会出现精度丢失用字符串最稳。第二type字段要预留因为不同内容类型的列表项UI展示位置可能不同。比如视频类内容要在封面上叠一个播放时长标签音频类要显示音频波形图。第三extraMap是故意留的“后门”业务方经常临时加字段集中收口在map里不用频繁改数据模型。3.2 Zustand Store的完整实现收藏状态的核心store我用Zustand实现代码量控制在100行以内。核心代码如下import { create } from zustand; import AsyncStorage from react-native-async-storage/async-storage; const STORAGE_KEY collection_list_v1; interface CollectState { collectMap: Recordstring, CollectItem; loading: boolean; init: () Promisevoid; addCollect: (item: CollectItem) Promisevoid; removeCollect: (id: string) Promisevoid; isCollected: (id: string) boolean; clearAll: () Promisevoid; } export const useCollectStore createCollectState((set, get) ({ collectMap: {}, loading: false, init: async () { set({ loading: true }); try { const raw await AsyncStorage.getItem(STORAGE_KEY); if (raw) { const parsed JSON.parse(raw); set({ collectMap: parsed }); } } finally { set({ loading: false }); } }, addCollect: async (item) { const nextMap { ...get().collectMap, [item.id]: item }; set({ collectMap: nextMap }); await AsyncStorage.setItem(STORAGE_KEY, JSON.stringify(nextMap)); }, removeCollect: async (id) { const nextMap { ...get().collectMap }; delete nextMap[id]; set({ collectMap: nextMap }); await AsyncStorage.setItem(STORAGE_KEY, JSON.stringify(nextMap)); }, isCollected: (id) { return Boolean(get().collectMap[id]); }, clearAll: async () { set({ collectMap: {} }); await AsyncStorage.removeItem(STORAGE_KEY); }, }));几个细节提一下。存储结构用的是对象Record而不是数组因为收藏列表的“判断是否已收藏”是一个极其高频的操作用对象做O(1)查找比用数组find快得多。列表展示时再把Object.values取出来做排序即可。每次add/remove都要同步写入AsyncStorage这是最直接的方案代码简单、可靠性高。缺点是高频操作时写盘频繁但收藏本来就是个低频操作用户不会一秒钟点十次收藏所以完全没问题。addCollect和removeCollect没有做merge处理而是全量覆盖。在这个场景下是OK的因为收藏总量有限单个key存几千条数据的JSON也就几百KB全量写一次在可接受范围内。如果未来收藏量到了上万条再考虑改用增量写入机制。3.3 初始化时机写在根组件还是页面组件收藏store的初始化建议提前到根组件而不是在收藏列表页。因为收藏状态可能在很多地方用到比如首页的收藏入口要显示数量角标详情页的收藏按钮要显示当前状态。如果只在列表页初始化那首页和详情页都可能出现“启动时一片空白等初始化完成才刷出来”的尴尬情况。实操中我会在根组件的useEffect里调用useCollectStore.getState().init()并加一个全局的loading状态初始化完成前不渲染相关UI。这样虽然整体启动时间会多出几十毫秒到几百毫秒但换来了状态的一致性值得。4. 列表页实现与核心交互4.1 FlatList在RNOH上的正确用法FlatList是RN生态里最常用的长列表组件RNOH也做了对应适配。但这里有个重要提示RNOH的FlatList在底层映射到ArkUI的List组件所以在部分API行为上会和Android/iOS表现不太一致。我用下来有几个体会第一getItemLayout一定要配。它是FlatList的一个性能优化属性能让列表在没有真实渲染每一项的情况下计算出每一项的高度从而提前定位滚动位置。对收藏列表这种高度不固定的内容推荐固定列表项高度比如封面固定120x80、文字部分最多三行。这样getItemLayout就能准确生效。第二keyExtractor必须稳定。我见过不少项目用index当key这会导致列表项复用混乱尤其是在删除操作后列表项的本地状态会错乱。收藏列表用item.id做key是底线。第三removeClippedSubviews在RNOH上有一些兼容性问题不建议直接设true。这个属性在Android上默认是true但RNOH的适配还不算完善开启后可能出现滑动时部分列表项闪烁。我们在项目里直接把它设为false列表数据量在几十条的时候性能损失可以忽略但稳定性提升很明显。第四initialNumToRender设置成10windowSize设置成5这两个参数决定了FlatList的“虚拟化窗口”大小。设置太小会导致滚动时频繁渲染设置太大会浪费内存。收藏列表的列表项数量通常不会超过几百10和5是比较稳妥的起点。4.2 收藏按钮交互的实现与防重复点击收藏按钮是列表页交互的核心。用户在列表页点一下收藏/取消收藏按钮状态要有即时反馈不能等网络请求完成才变。我们采用的是“本地先行 网络同步”的策略。const handleToggleCollect async (item: CollectItem) { // 防重复点击 if (actionLockRef.current) return; actionLockRef.current true; const isCollected useCollectStore.getState().isCollected(item.id); if (isCollected) { await useCollectStore.getState().removeCollect(item.id); } else { await useCollectStore.getState().addCollect(item); } // 网络同步失败恢复 try { if (isCollected) { await requestCancelCollect(item.id); } else { await requestAddCollect(item.id); } } catch (err) { // 网络失败回滚本地状态 if (isCollected) { await useCollectStore.getState().addCollect(item); } else { await useCollectStore.getState().removeCollect(item.id); } Toast.show(网络异常操作失败); } finally { actionLockRef.current false; } };这段代码的核心思路是“乐观更新”。我先改本地状态让UI立刻响应再发网络请求。请求失败就回滚状态并提示用户。这样用户体验最好也不会出现点按钮半天没反应的情况。防重复点击用的是actionLockRef一个简单的ref标记。在异步操作结束前后续点击都被忽略。收藏操作本身很快锁的粒度不需要太细锁定整个函数就够了。4.3 下拉刷新与上拉加载更多下拉刷新用RefreshControl组件RNOH适配得还可以。需要注意的一点是收藏列表的业务场景是“拉取最新收藏”而不是“重新拉全量”所以刷新成功后的逻辑应该是增量合并。具体做法是一份增量合并的逻辑代码const handleRefresh async () { setRefreshing(true); try { const latest await fetchCollectList({ page: 1, pageSize: 20 }); // 合并本地收藏数据以服务端为准 保留未同步的本地数据 const localMap useCollectStore.getState().collectMap; const mergedMap { ...localMap }; latest.forEach((item) { // 服务端返回的收藏如果本地没有就补进去 if (!mergedMap[item.id]) { mergedMap[item.id] item; } // 如果本地有但服务端没有说明这个收藏是旧的以本地为准保留 }); // 全量更新store和缓存 useCollectStore.setState({ collectMap: mergedMap }); await AsyncStorage.setItem(STORAGE_KEY, JSON.stringify(mergedMap)); setListData(Object.values(mergedMap).sort((a, b) b.collectedAt - a.collectedAt)); } catch (err) { Toast.show(刷新失败请检查网络); } finally { setRefreshing(false); } };上拉加载更多直接复用FlatList的onEndReached回调需要两个判断条件有更多数据和不在请求中。收藏列表的排序规则是“最新收藏的在最上面”这个排序在store里做列表页只负责展示排好序的数据。从实际体验来看这种设计让列表页代码很干净只需要从store里取数据不用管数据来源。4.4 空列表与异常状态的兜底处理收藏列表比较特殊它可能因为各种原因出现空状态、加载失败、网络异常等情况。空状态要有引导不能让用户觉得“这个页面是不是坏了”。我们的处理方案是三种状态共用同一个View。收藏列表为空显示“暂无收藏快去发现精彩内容吧” “去逛逛”按钮点击跳转到推荐页。初始化失败显示“加载失败” “重试”按钮。网络离线时下拉刷新弹出Toast提醒“当前网络不可用”并展示上一次的缓存数据。实现起来其实就是用一个viewState字段标志当前状态然后在render里做条件判断。收藏列表业务逻辑不复杂分支不要划得太多否则代码会变得难维护。5. 收藏状态的一致性问题5.1 跨页面同步不止是Zustand的事Zustand解决了“状态存储”的问题但“跨页面同步”还牵扯到数据流方向。比如用户从收藏列表点击进入详情页在详情页里取消收藏然后返回列表此时列表页的UI要能刷新到最新状态。这套机制靠Zustand的响应式订阅就能自动完成。收藏列表页监听collectMap的变化一旦变化就重新计算并渲染列表。这里有一个容易被忽视的问题列表页不要同时用“本地state副本”和“store状态”做数据源否则两边的同步会非常混乱。列表页的数据源应该永远是collectMap不要复制到state里。我踩过这个坑。最初版本里我把收藏列表的数据从store拿出来放到了组件的useState里结果在详情页取消收藏后返回列表列表页的state没有更新UI还显示着“已收藏”。后来改成直接订阅store这个问题就自然消失了。5.2 详情页收藏按钮的联动详情页的收藏按钮和列表页逻辑类似但要注意一个场景如果用户从收藏列表进入详情且在详情页对内容进行“取消收藏”操作这是合法的。但用户在详情页点击取消收藏后如果又点击“收藏”那内容会重新被收藏收藏时间会更新为最新时间列表页的顺序会变化。这个交互细节需要在详情页做处理。我们的做法是详情页的收藏按钮订阅同一个store不做任何本地状态复制。点击时直接调用store的addCollect或removeCollect。页面返回列表时列表页因为订阅了同一份store自动刷新不需要手动通知。5.3 收藏数量角标与红点提醒首页通常有收藏入口显示收藏数量角标。这个角标也建议直接订阅store。收藏数量有一个“几百以内秒刷新”的体验要求Zustand能做到。另外如果产品要求“收藏内容有更新要给红点提醒”这个建议不要放在客户端做而是让服务端推送通知。客户端只需要在收到推送后调用一次刷新接口即可。6. 性能优化与渲染异常排查6.1 启动白屏问题RNOH上尤其明显React Native启动白屏是社区里讨论非常多的问题在RNOH上更不能忽略。RNOH的启动链路和Android原生RN并不完全相同从设备启动到RN页面真正渲染出第一帧中间要经过“应用加载 RNOH运行时初始化 bundle加载与解析 JS引擎执行 首次渲染提交”等环节。我实测下来在低端设备上RNOH的bundle加载和解析耗时比Android原生RN要高一些。原因很直接RNOH的bundle需要同时兼容RN runtime和ArkUI runtime它要在JS层和ArkTS层之间做一次桥接初始化这个额外开销绕不过去。所以应对启动白屏的思路要从“减少首屏等待”和“启动loading体验”两个方向同时下手。首先推荐做bundle分包和预加载。RNOH支持加载本地bundle如果bundle体积压缩到1MB以内加载速度会有明显体质改善。React Native的bundle在做完分包后首屏核心代码保持在最小范围其余业务代码按需加载。其次启动页的Splash策略要调整。不能干等JS执行完而是要提前给用户一个“看起来已经启动”的反馈。我们的方案是原生启动页展示品牌Logo 轻量动画JS执行完后通过交互事件快速切换原生Splash与RN页面。这个切换要做好两边的视觉衔接避免出现闪一下白屏再进页面的情况。还有一个细节不要在根组件的componentDidMount里做大量同步操作。图片预加载、大对象初始化、敏感权限申请这些都应该推迟到首屏渲染完成之后。我用InteractionManager.runAfterInteractions做了个包装把非关键任务都放在首批交互完成之后再执行。6.2 FlatList首屏渲染优化与minBatchSizeFlatList的首屏渲染性能直接影响收藏列表页的打开速度。除了前面提到的getItemLayout和windowSize还有两个参数值得关注。maxToRenderPerBatch控制每批渲染的组件数默认值是10。把这个值调低到5能让首屏更快地拿到第一批可视组件但代价是快速滑动时可能出现短暂的空白。收藏列表不追求极致的滑动性能所以我把maxToRenderPerBatch设成5updateCellsBatchingPeriod设成50毫秒实际体验下来更丝滑。另外列表项组件本身要避免使用“无谓的重渲染”。每个列表项用React.memo包裹在props没有变化时跳过渲染。收藏按钮的props只传入收藏状态不传整个store对象这个细节对长列表的滚动流畅度影响很大。6.3 画面渲染异常RNOH需要特别注意的三个点“OpenHarmony画面渲染异常”是个高频热搜词我在实际开发中也遇到过好几次。整理一下最常见的三类问题以及我的处理方式。第一图片闪烁或拉伸。RNOH的Image组件在解析网络图片时如果没设置width和height布局引擎在拿到图片尺寸之前会先用0宽高占位图片加载完成后再突然撑开看起来就是“闪烁”或者“跳动”。解决办法很简单给所有Image设置固定宽高或者使用aspectRatio锁定比例。封面图我会先通过Image.getSize获取尺寸再按比例计算出宽高。第二列表滚动时内容闪烁或重排。这个大概率是removeClippedSubviews的兼容性问题。RNOH的List组件在回收列表项时如果ArkUI侧的复用逻辑和RN侧的虚拟化逻辑不同步就会出现闪烁。解决方案就是关闭removeClippedSubviews同时配合固定高度降低重排概率。第三文本字体和行高不一致。RNOH在渲染自定义字体时处理方式和Android原生RN不完全相同如果项目中引入了第三方字体库某些机型的行高会偏高或偏低。收藏列表的标题、作者名、时间三行文字建议用统一的行高值不要依赖系统默认值。6.4 收藏列表滑动卡顿排查滑动卡顿是一个非常影响体验的问题。我在收藏列表上主要做了几个优化列表项用React.memo包裹收藏按钮的状态单独订阅避免其他状态变化触发整行重渲染。图片统一使用缩略图地址。收藏列表里的封面图控制在200KB以内太大的图直接换一个压缩版本。避免在renderItem里做函数绑定。每次渲染都创建新函数会导致子组件无法命中memo要把onToggle函数用useCallback包裹并且依赖项尽量少。减少阴影和复杂样式。收藏列表项如果用了大量shadow*属性在RNOH上可能会触发额外的离屏渲染。用1px的border模拟分割线成本比阴影低得多。7. 常见问题与排查技巧实录7.1 RNOH启动白屏与bundle加载问题速查问题现象可能原因解决方案启动后白屏超过3秒bundle体积过大或未做分包压缩bundle、做分包预加载、Splash做视觉过渡启动后偶发白屏重进正常RNOH运行时初始化时序不稳定延迟JS执行确保ArkUI侧渲染容器已就绪杀掉进程后重启白屏AsyncStorage缓存数据读取阻塞首屏分层缓存首屏只读轻量摘要数据Debug模式正常Release白屏Release包缺少bundle或bundle路径错误检查assets目录下bundle是否打包完整7.2 FlatList在RNOH上的兼容性问题FlatList在RNOH上踩过两个印象比较深的坑。第一个是onEndReached在内容不满一屏时也会触发。严格来说这不算bugRN的FlatList本来就是这个行为但很多新手会在这里翻车当收藏列表只有三五条数据时页面一直在请求“下一页”发出无效请求甚至导致无限循环。解决方案是加一个判断当data.length pageSize时直接标记没有更多数据不再触发onEndReached。第二个是部分RN版本在删除列表项后会出现Animated动画残留。收藏列表没有做复杂的删除动画所以问题不明显但如果你要做“取消收藏后列表项淡出”的动画效果建议先小范围验证兼容性确认没问题再全量上线。7.3 收藏数与实际内容不一致这个问题的根源通常是本地缓存和网络不同步。我遇到过两种实际场景场景一用户清缓存后打开收藏列表为空。这是因为收藏数据只存在本地服务端还没拉回来。解决方案是初始化时要先读缓存展示空态然后立刻拉网络数据填充。场景二某个内容取消了收藏刷新后又“回来”了。这是典型的服务端“收藏状态”接口返回了脏数据。排查方式是看请求参数确认请求的是“当前用户状态的收藏列表”而不是“全部收藏列表”。这个问题的终极解法是本地做权威数据源服务端做增量同步。每次拉取时过滤掉本地已经取消收藏的内容除非服务端明确说明“这条内容是最近新增的收藏”。7.4 一个数据校验的埋点技巧收藏列表上线前我建议加一个简单但不显眼的数据一致性校验埋点。每次本地收藏集合变化时把collectMap的key数量、数据总量统计一下上报给后端。两边一对比如果差距持续拉大基本可以断定存在状态同步bug。这个埋点成本很低但对排查“收藏数神秘丢失”“收藏数莫名增加”这类问题效果极其显著。8. 一条龙实操复盘与避坑清单8.1 从零到一的关键步骤回顾整个收藏列表模块从需求确认到跑通我们团队花了一周每天大概半天投入。复盘下来几件关键的事放在一起列出来第一需求边界写清楚特别是离线策略和数据同步规则这是最重要的第一步。第二确定技术栈RN生态里最成熟的库优先RNOH专属适配库谨慎引入。第三数据模型一次性想清楚id用字符串、type字段预留给后期扩展留空间。第四Zustand的store统一管理收藏状态列表页、详情页、首页全部订阅同一份store。第五FlatList配置一遍到位getItemLayout、keyExtractor、windowSize、maxToRenderPerBatch这些参数按推荐值设置。第六乐观更新 失败回滚的交互模式让用户点击收藏按钮的反馈更快更稳定。第七性能优化按“启动白屏、列表首屏、滑动流畅度”三个维度依次做不要一上来就优化细节。8.2 避坑清单都是真金白银踩出来的AsyncStorage不要在大数据量场景下频繁全量写入一定要分层存储首屏只读最轻量的字段。FlatList的removeClippedSubviews在RNOH上不要开true闪烁问题排查起来非常困扰人。图片组件必须给固定宽高或aspectRatio否则加载完成时会触发渲染重排表现为闪烁或跳动。列表页数据源必须直接订阅store不要复制到本地state再做同步否则一定会出现UI不同步的问题。所有函数用useCallback/useMemo包裹列表项用React.memo接住这是长列表流畅度的基础保障。不要在根组件里做阻塞首屏的同步任务耗时操作全部推迟到首屏渲染完成后。上线前加一个本地和服务端收藏数的一致性校验埋点很多隐蔽问题靠这个能提前暴露。坦白说RNOH这个框架还在快速演进很多API的底层实现会和标准RN有所不同。作为开发者我们能做的就是“把能做的优化做到位把能避的坑提前避掉”同时在遇到框架本身的问题时多去社区反馈、看issue、翻源码。收藏列表这个项目跑通之后我对RNOH的信心其实增强了不少——它可能还没到生产级完美程度但完成一个中等复杂度的业务模块已经完全够用了。如果你正准备做RNOH适配从收藏列表这类功能起步是一个很理性的选择。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价