React Native 开发的电商类 App 我一直觉得是移动端最能检验功力的场景:商品列表要流畅、详情页要丰富、购物车和订单的状态流转要严谨、再加上推荐系统和商家模块,一套组合拳下来,几乎把客户端开发会遇到的重难点全涵盖了。这两年鸿蒙生态起来之后,跨端适配又从“可选加分项”变成了“必修课”,很多团队都在焦虑怎么用一套代码同时覆盖 iOS、Android 和鸿蒙。这篇文章就围绕 React Native 全能商城项目的完整实现来拆解,重点聊聊业务架构设计、核心交互的落地方式,以及鸿蒙跨端适配时那些文档里不会明说、但实测下来必须处理的细节。
这个项目适合两类人:一类是正在用 React Native 做中大型 App、尤其想参考商城这种复杂业务怎么组织代码的开发者;另一类是公司开始要求“一套代码多端运行”、正在评估鸿蒙适配方案的移动端技术负责人。我会把工程项目里真实会碰到的设计取舍和踩坑记录都写出来,尽量让不同基础的读者都能找到自己需要的那一块。
1. 商城 App 整体设计与技术选型思路
1.1 为什么选择 React Native 做全能商城
电商类应用的需求迭代速度非常快,运营活动、促销玩法、页面改版几乎是每周都在变。原生双端开发在这种节奏下最大的问题是排期:一个需求 iOS 排三天、Android 排三天,联调测试再来几天,等上线的时候业务黄金期可能都过了。React Native 的价值在于 JavaScript 代码直接复用,业务逻辑层基本上写一遍就能双端运行,UI 层面虽然偶尔要处理平台差异,但整体效率依然比双原生开发高一截。
另外商城 App 对动态化有天然需求。首页的 banner 位、金刚区图标、楼层模块,这些都不能靠发版更新。React Native 配合 CodePush 或者热更新方案,可以做到不发商店审核直接推送 JS 更新,这在电商场景里几乎是刚需。我做这个项目的时候就是把页面配置化能力放在第一优先级,首页的每个模块都由后端下发 JSON 配置驱动,RN 端只负责渲染,这样运营调整页面不用等客户端排期,体验会顺畅很多。
选 React Native 而不是 Flutter,主要考量点是生态成熟度。电商类项目需要大量的第三方 SDK:支付、统计、推送、地图、客服聊天,这些在 React Native 生态里基本都有现成库,踩坑记录也多,遇到问题搜索一下基本能解决。Flutter 虽然渲染性能更优,但部分国内 Android SDK 的插件维护情况参差不齐,尤其是涉及鸿蒙适配的第三方库更是少之又少。
1.2 鸿蒙跨端适配的核心矛盾
鸿蒙生态现在的处境比较特殊:一方面设备量增长很快,另一方面纯血鸿蒙不再兼容 Android APK,这意味着所有 App 都要重新适配。对 React Native 项目来说,鸿蒙适配的核心矛盾在于JavaScript 引擎和原生 UI 组件的映射关系。
React Native 在 iOS 和 Android 上依赖的底层实现分别是 JavaScriptCore 和 Hermes,渲染层通过 Fabric 架构映射到各自的原生视图。鸿蒙这边没有现成对应的渲染树,需要借助 OpenHarmony 的组件体系重新实现一套 React Native 的宿主环境。目前社区主流的方案是通过 react-native-harmony 这类中间层,把 React Native 的虚拟 DOM 映射到 ArkUI 的组件上,同时把 JavaScript 引擎切换到鸿蒙系统自带的 ArkTS 运行时。
这里有个关键认知需要纠正:鸿蒙适配不是“改几个文件就能跑起来”的事,它涉及工程构建链路的完整改造。原来 iOS 用 CocoaPods、Android 用 Gradle,鸿蒙这边用的是 DevEco Studio 的 Hvigor 构建系统,三方库的依赖方式、原生模块的注册机制、资源文件的打包方式全都不一样。做适配之前一定要把工程结构上的差异先摸清楚,否则后面每次编译都会遇到各种莫名其妙的环境问题。
1.3 技术栈全景与架构分层
基于商城业务的特点和跨端诉求,这套项目的技术栈选型如下:
- 核心框架:React Native 0.72+,开启 New Architecture(Fabric + TurboModule)
- 语言方案:TypeScript 全量覆盖,业务代码和配置类型都走严格模式
- 路由管理:React Navigation 6.x,底部 Tab + 原生栈结合
- 状态管理:Redux Toolkit + RTK Query,服务端状态和客户端状态分开管理
- UI 组件库:自建了一套基础组件库,包含按钮、输入框、弹窗、Toast、图片懒加载等
- 网络层:axios 封装,统一处理 token 刷新、错误码映射、请求竞态
- 原生能力桥接:支付、推送、分享、地图通过 NativeModule 封装,保留扩展接口
- 鸿蒙侧适配:接入
react-native-harmony运行时,动态切换构建目标
架构分层上我沿用了经典的 MVVM 思路,但做了微调。页面层(View)只负责渲染和交互事件派发,业务逻辑收敛到自定义 Hooks 或者 Redux 的异步 Action 中,网络请求和缓存逻辑则下沉到 Service 层。这样做的原因是商城业务里同一份数据可能在多个页面复用,比如商品详情页加入购物车后,TabBar 上的购物车角标要同步更新,如果每个页面各自管理数据,这种跨页面的状态同步会搞得非常痛苦。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 商城核心业务模块的设计与实现
2.1 首页动态化方案:JSON 驱动配置渲染
首页是商城 App 的流量入口,也是改版最频繁的地方。我的实现思路是把首页拆成一个个独立组件单元,包括搜索栏、Banner 轮播、金刚区图标、宫格推荐、秒杀倒计时、商品瀑布流等,每个组件对应一种 JSON 配置类型。后端下发完整的首页配置,客户端拿到配置后按顺序渲染对应组件。
json复制{
"pageId": "home_page_v1",
"modules": [
{ "type": "searchBar", "placeholder": "搜索商品", "action": "search" },
{ "type": "banner", "data": [ { "imageUrl": "https://xxx/banner1.png", "link": "product?id=123" } ] },
{ "type": "gridNav", "columns": 5, "items": [ { "icon": "https://xxx/icon1.png", "title": "限时秒杀", "action": "seckill" } ] },
{ "type": "productList", "layout": "twoColumns", "api": "/api/home/products" }
]
}
这套方案的难点不在渲染层,而在配置的版本管理和容错处理。后端配置经常会有字段调整,客户端如果解析失败,不能白屏,要能自动降级到上一次可用的缓存配置。我在项目里实现了一个配置管理器,专门负责拉取、校验、缓存和回滚配置。每次拉取新配置后先用 JSON Schema 校验,校验失败就继续用旧配置,同时上报错误日志。
首页的性能也要重点盯。Banner 轮播和商品瀑布流都是图片密集场景,必须结合 FlatList 的 windowSize 和 removeClippedSubviews 做性能优化,同时图片库用 react-native-fast-image 做三级缓存,否则用户滑动首页的时候掉帧会非常明显。
2.2 商品列表与无限滚动加载
商品列表页要处理的细节非常多,从分类切换、筛选排序到分页加载、骨架屏、加载失败重试,每一步都有坑。我采用的是 FlatList 作为核心列表组件,用 onEndReached 触发分页加载。这里有一个关键参数容易踩坑:onEndReachedThreshold 的取值。这个值表示距离底部还有多远时触发加载,取值范围是 0 到 1,我一般设成 0.3。
分页加载时要注意接口重复请求的问题。快速滑动到底部时,onEndReached 可能在短时间内被多次触发,如果不加锁,会出现同一页数据被请求两次。我的做法是在加载状态里加一个 isLoadingMore 的 flag,请求期间直接返回,请求完成后根据返回结果决定是否还有下一页。另外,列表项的 key 必须稳定,不能在渲染过程中变化,否则会引发 React 的 reconciliation 混乱,导致列表项状态丢失甚至白屏。推荐用商品 ID 作为唯一 key。
商品列表还有一种常见的交互是“筛选条件变化后重新加载第一页”,这里必须重置分页游标并且清空已有列表数据,我见过不少项目因为漏了这一步,导致用户切完分类后看到的还是上一个分类的商品。
2.3 商品详情页的复杂交互处理
商品详情页是商城里面 UI 交互最复杂的页面之一:顶部轮播图、价格区域、规格选择弹窗、图文详情、评价列表、底部操作栏(客服、店铺、购物车、立即购买)都要协同工作。实现上我把它拆成了三个独立的纵向滚动容器,通过一个母容器 ScrollView 统一协调,首屏的商品信息区域用原生视图直接渲染,减少嵌套层级。
规格选择是细节最多的部分。SKU 的联动逻辑要处理“有货/无货/不可选”三种状态,核心是维护一个 SKU 矩阵:前端拿到的数据是每个 SKU 组合的库存和价格,用户每点击一个规格,就要根据已有的组合计算其他规格的可选性。实现时我用了一个 Map 存储 SKU 数据,Key 是规格值的组合签名,比如“红色-32G-全网通”,这样查询和计算复杂度都是 O(1),性能可以接受。
购物车和立即购买的数据流有一个需要注意的点:从详情页加购或者下单时,需要把选中的 SKU 信息回传到列表页,同时更新购物车角标。这个场景我是用全局事件总线实现的,发布一个 CART_UPDATED 事件,购物车数据和角标组件订阅这个事件做更新,比层层回调传参要优雅得多。
2.4 购物车与订单状态流转
购物车的状态管理适合放在 Redux 里集中处理,因为它的数据来自两个渠道:本地缓存的未登录购物车列表和接口返回的登录后购物车列表。为了处理合并逻辑,我把购物车数据设计成了服务端数据的镜像,本地只保存一份草稿状态,所有变更先更新 UI,再异步同步到服务端,失败时回滚。这种“乐观更新”的策略在购物车这种高频率操作场景下体验远好于同步等待。
订单流程的状态机设计也值得记录一下。从“待付款”到“待发货”到“待收货”再到“已完成”,中间穿插着取消、退款、售后这些分支,纯靠 if-else 去管理状态会非常乱。我用一个简单的状态机库来定义订单状态流转表,每个状态对应允许的动作和跳转目标页,非法操作直接拦截,这在后续业务扩展时可以少踩很多坑。
3. 鸿蒙跨端适配的实操过程记录
3.1 工程结构改造与构建链路搭建
鸿蒙适配的第一步是改造工程结构。React Native 标准项目通过 react-native init 生成后是 iOS + Android 双工程结构,鸿蒙侧需要额外增加一套工程目录,并用 Hvigor 构建。我没有直接手写配置,而是用了社区维护的 react-native-harmony 脚手架来生成鸿蒙工程骨架,然后手动把业务代码和第三方依赖迁移进去。
一个比较关键的实操点是:React Native 的新架构(New Architecture)在鸿蒙侧的兼容性。社区实现目前对 Fabric 和 TurboModule 的支持还在逐步完善阶段,如果你在 Android 上已经开启新架构,鸿蒙侧可能要先退回旧架构,等稳定版发布再迁移。建议项目一开始就做一次架构抽象,在原生模块调用层做兼容,不要直接调用底层 API,这样后续切换架构时可以少改业务代码。
code复制项目根目录/
├── android/ # Android 工程
├── ios/ # iOS 工程
├── harmony/ # 鸿蒙工程(新增)
├── src/ # React Native 业务代码
├── package.json
└── react-native.config.js
3.2 原生模块的三端兼容封装
商城项目里支付、推送、统计、地图这些能力都依赖原生模块,鸿蒙端需要逐个适配。我在设计原生模块的时候统一采用了“协议 + 实现”的模式:TypeScript 层定义好接口协议,iOS、Android、鸿蒙各自实现一套原生代码。业务侧只面向协议编程,不关心底层是哪个平台。
typescript复制// payment.ts
export interface PaymentService {
init(config: PaymentConfig): Promise<void>;
pay(order: OrderInfo): Promise<PayResult>;
}
// harmony/PaymentServiceImpl.ets
export class PaymentServiceImpl implements PaymentService {
async pay(order: OrderInfo): Promise<PayResult> {
// 调用鸿蒙支付 SDK
}
}
这种封装方式在适配鸿蒙时帮了大忙。第三方 SDK 在鸿蒙上没有现成版本的情况很常见,比如地图 SDK 和部分推送 SDK,这些模块我会先用 WebView 加载 H5 版本作为过渡方案,等官方鸿蒙 SDK 发布后再替换。业务侧由于走的是抽象接口,替换时基本不需要动上层逻辑。
3.3 鸿蒙侧调试与构建常见问题
鸿蒙适配过程中我遇到最多的问题是构建环境和资源引用。DevEco Studio 对 Node.js 版本、SDK 版本要求比较严格,版本不匹配会出现各种莫名其妙的编译错误。调试时有两个工具必用:hdc 命令行工具负责安装和调试鸿蒙应用,hilog 负责查看系统日志,对应 Android 里的 adb 和 logcat。建议刚接触的开发者先把这两个工具链跑通,后面排查问题会顺手很多。
4. 性能优化与常见问题排查
4.1 React Native 白屏问题定位
启动白屏是 React Native 项目出现频率极高的问题,商城 App 对这种问题的容忍度更低,直接会影响首单转化。白屏的成因五花八门,我按出现频率梳理了一份排查清单:
- Bundle 加载失败:最常见的是 JS Bundle 地址配置错误或者本地 Bundle 不存在,Android 上 Debug 模式连不上 Metro 也会白屏
- 原生端初始化崩溃:React Native 初始化过程中某个原生模块崩溃会导致整个页面无法渲染,排查方式是看
hilog或logcat里有没有 Java/ArkTS 的异常堆栈 - JS 层异常未捕获:入口组件渲染时抛错但没有全局错误边界,整个应用直接白屏
- 新架构与鸿蒙运行时冲突:部分原生模块没有实现新架构的接口,在鸿蒙侧初始化失败
我的排查顺序是:先看原生日志,确认 JS Bundle 有没有加载成功;再打开 Chrome DevTools 或鸿蒙的 ArkUI Inspector,看页面组件树有没有渲染;最后在入口组件加一个 ErrorBoundary,把渲染错误直接展示到页面上方便定位。
4.2 首页加载性能优化
商城首页的加载速度直接关系到用户留存。我做了三方面优化,实测效果非常明显:
- JS Bundle 拆包:把第三方库、业务代码、鸿蒙适配层拆成多个 Bundle,首页只加载首屏必需的代码,进入二级页面时再按需加载
- 图片 CDN 优化:所有商品图按需裁剪尺寸,列表页使用 400px 宽度的缩略图,详情页用 800px,大图延迟到用户点击预览时才加载
- 接口预请求:App 启动时立即发起首页配置和商品列表请求,不等待 JS Bundle 完全执行完,能缩短几百毫秒的首屏数据等待时间
启动白屏和首页加载慢经常混在一起,但成因完全不同。白屏是“渲染不出来”,加载慢是“渲染出来了但在等数据”,排查时把这两个目标分开盯,效率会高很多。
4.3 循环滚轮:商品数量选择器的实现
热搜里提到了 React Native 循环滚轮,这个在商城里的典型场景就是商品数量选择器。iOS 上可以用原生的 UIPickerView,Android 上社区里没有特别好用的循环滚轮库。如果只是选数量,我建议不要用滚轮,直接用步进器(Stepper)更符合移动端习惯。但如果是选择日期、地区这类选项较多的场景,滚轮确实更合适。
React Native 里实现滚轮我分享一个通用思路:用 ScrollView 或者 FlatList 的 snapToInterval 属性做整行吸附,监听滚动结束事件计算当前选中的下标,然后把内容做首尾循环拼接模拟无限滚动。这套方案的好处是无依赖,坏处是快速滑动时可能出现吸附不准,需要根据实际情况微调 decelerationRate 和 snapToInterval 的取值。
4.4 常见问题速查表
我把项目开发过程中遇到的问题整理成一张速查表,方便大家直接对号入座:
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 首页白屏 | JS Bundle 加载失败 | 检查 Bundle 地址和本地文件是否存在 |
| 首次进入二级页面卡顿 | 页面未做按需加载 | 使用 React.lazy 或拆包方案 |
| 商品列表滑动掉帧 | FlatList 未优化 | 设置 windowSize、removeClippedSubviews |
| 购物车角标不同步 | 状态管理未统一 | 使用全局事件或集中式状态管理 |
| 鸿蒙侧编译报错 | SDK 版本不匹配 | 检查 DevEco Studio 和鸿蒙 SDK 版本 |
| 支付完成后无回调 | 原生模块事件未注册 | 检查 NativeEventEmitter 注册逻辑 |
| 图片加载缓慢 | 未使用缓存图片库 | 接入 react-native-fast-image |
| 列表页触底重复请求 | 分页加载未加锁 | 添加 isLoadingMore 状态拦截 |
| SKU 选择状态错乱 | 规格值 key 不稳定 | 用组合签名作为 key |
| 热更新后页面异常 | 新版本 JS 兼容性问题 | 建立版本灰度与回滚机制 |
5. 从项目沉淀下来的实操建议
5.1 架构设计阶段的三个关键决策
回过头看这个项目,有几个在架构设计阶段做的决策对后续开发帮助最大。
第一个是全面拥抱 TypeScript。商城业务的数据结构非常复杂,商品信息、SKU、订单、购物车,每个领域模型都有几十个字段。TypeScript 的编译期类型检查,在接口字段变动频繁的电商场景里,能提前拦住大量拼写错误和数据结构不匹配的问题。团队协作时类型定义本身就是最好的文档。
第二个是状态管理的分层策略。我早期也走过“什么状态都往 Redux 里塞”的弯路,后来发现很多局部 UI 状态根本不需要全局管理。现在的策略是:服务端数据走 RTK Query 的缓存,跨页面共享的客户端状态(登录态、购物车数量)走 Redux,页面内部 UI 状态走 useState/useReducer。这个分层让代码的可维护性提升非常明显。
第三个是组件库的规范性。商城需要的基础组件大概有 20 多个,如果每个页面自己写一套,样式会越来越乱。我维护了一套统一的基础组件库,并给每个组件配了 Storybook 示例。新页面开发时,先看组件库里有什么,再决定要不要新增组件,保证视觉风格和交互体验的一致性。
5.2 鸿蒙适配时容易被忽视的隐性成本
国内团队在评估鸿蒙适配的时候,最容易低估的是测试成本。鸿蒙生态的机型碎片化程度虽然在控制中,但不同版本的 OpenHarmony 对 ArkUI 组件、系统 API 的支持仍有差异。我的建议是拉一个真机测试矩阵,至少覆盖 HarmonyOS NEXT 的几款主流机型,重点测支付流程、推送到达率、分享功能、定位权限这些系统级能力。
另一个容易忽视的点是包体积和首包下载时长。鸿蒙适配后,工程里多了一套原生代码和资源,包体积会比纯双端版本大一圈。如果团队比较在意下载转化率,可以在发行阶段对鸿蒙包做系统性的裁剪:移除调试符号、压缩资源文件、按需加载框架模块。这个优化空间通常有 20% 到 30%。
5.3 项目后续可以扩展的方向
这个商城项目的基线版本已经能支撑一个中型电商业务的基础需求,后续如果要扩展,我会优先考虑几个方向。
第一是接入推荐算法。当前的商品推荐还是基于业务规则的运营配置,可以尝试接入简单的协同过滤或者热门排行推荐,根据用户的浏览和购买历史做个性化排序,这对转化率的提升通常比 UI 优化更直接。
第二是完善商家模块。商城如果要做平台化,商家侧的需求和用户侧几乎是两个量级。商家订单管理、商品上下架审核、营销工具配置、数据看板,这些功能可以独立成一个商家版 App,复用小程序的业务协议,降低成本。
第三是探索鸿蒙生态的深度能力。鸿蒙的分布式能力在跨设备流转场景下有独特的优势,比如手机上的购物车可以直接流转到平板继续编辑,扫码枪等外设可以和 App 联动。这些都是传统 Android 生态里较难实现的差异化功能,值得花时间研究。
根据我个人在这个项目里的体会,做跨端商城最核心的心得是:架构设计阶段多花时间,后面迭代可以省下十倍的时间。React Native 本身的上手难度不高,但要在商城这种复杂业务场景下跑得稳,关键还是对业务模型的把握和对平台差异的预判能力。鸿蒙适配这条路目前成熟的案例还不够多,团队需要有持续跟进社区更新和技术演进的耐心,但只要基础架构打好了,多端运行的红利会非常明显。最后再分享一个小技巧:适配鸿蒙时尽量保持 React Native 版本和社区同步,不要长期停留在旧版本,因为鸿蒙的适配进度是跟着新版 RN 走的,版本越新,踩到的兼容性坑越少。
