HarmonyOS APP开发---“好物优选“电商导购App,需要用到这个库

HarmonyOS APP开发---"好物优选"电商导购App,需要用到这个库

做一个电商导购 App,首页→分类列表→商品详情→购物车→结算,页面栈深度 5+。不开原生屏幕的话,所有页面都挂载在内存里------@react-native-ohos/react-native-screens 一行开启,不可见页面真正移除渲染树,内存直接降一半。
📦 仓库地址:https://gitcode.com/CPF-RN/rntpc_react-native-screens | 安装:npm install @react-native-ohos/react-native-screens


写在前面

"好物优选"是一个电商导购 App,典型用户路径:

首页 → 分类页 → 商品列表 → 商品详情 → 购物车 → 结算 → 订单详情

一条路径走下来,页面栈深度可达 5-7 层。如果用 react-navigation 默认的 JS 视图栈模拟,所有 7 个页面的 UI 组件都挂载在视图树里------即使你看不到它们,它们也在内存里占着位置,低端鸿蒙设备上直接 OOM。

更严重的是切换卡顿:JS 层动画受线程影响,商品详情页这种重页面 push 时明显掉帧。

react-native-screens 把屏幕管理下沉到鸿蒙原生层------不可见页面从渲染树 detach(保留状态),切换动画在原生层执行enableScreens(true) 一行开启,现有代码零改动。

这篇文章聊什么

  1. 开启原生屏幕------一行配置,导航性能直接提升
  2. 页面栈深度优化------7 层页面不再全部挂载内存
  3. Tab 冻结------非活跃 Tab 页面冻结渲染

#mermaid-svg-9UE89NloA4muaq6N{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-9UE89NloA4muaq6N .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-9UE89NloA4muaq6N .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-9UE89NloA4muaq6N .error-icon{fill:#552222;}#mermaid-svg-9UE89NloA4muaq6N .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-9UE89NloA4muaq6N .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-9UE89NloA4muaq6N .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-9UE89NloA4muaq6N .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-9UE89NloA4muaq6N .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-9UE89NloA4muaq6N .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-9UE89NloA4muaq6N .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-9UE89NloA4muaq6N .marker{fill:#333333;stroke:#333333;}#mermaid-svg-9UE89NloA4muaq6N .marker.cross{stroke:#333333;}#mermaid-svg-9UE89NloA4muaq6N svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-9UE89NloA4muaq6N p{margin:0;}#mermaid-svg-9UE89NloA4muaq6N .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-9UE89NloA4muaq6N .cluster-label text{fill:#333;}#mermaid-svg-9UE89NloA4muaq6N .cluster-label span{color:#333;}#mermaid-svg-9UE89NloA4muaq6N .cluster-label span p{background-color:transparent;}#mermaid-svg-9UE89NloA4muaq6N .label text,#mermaid-svg-9UE89NloA4muaq6N span{fill:#333;color:#333;}#mermaid-svg-9UE89NloA4muaq6N .node rect,#mermaid-svg-9UE89NloA4muaq6N .node circle,#mermaid-svg-9UE89NloA4muaq6N .node ellipse,#mermaid-svg-9UE89NloA4muaq6N .node polygon,#mermaid-svg-9UE89NloA4muaq6N .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-9UE89NloA4muaq6N .rough-node .label text,#mermaid-svg-9UE89NloA4muaq6N .node .label text,#mermaid-svg-9UE89NloA4muaq6N .image-shape .label,#mermaid-svg-9UE89NloA4muaq6N .icon-shape .label{text-anchor:middle;}#mermaid-svg-9UE89NloA4muaq6N .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-9UE89NloA4muaq6N .rough-node .label,#mermaid-svg-9UE89NloA4muaq6N .node .label,#mermaid-svg-9UE89NloA4muaq6N .image-shape .label,#mermaid-svg-9UE89NloA4muaq6N .icon-shape .label{text-align:center;}#mermaid-svg-9UE89NloA4muaq6N .node.clickable{cursor:pointer;}#mermaid-svg-9UE89NloA4muaq6N .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-9UE89NloA4muaq6N .arrowheadPath{fill:#333333;}#mermaid-svg-9UE89NloA4muaq6N .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-9UE89NloA4muaq6N .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-9UE89NloA4muaq6N .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-9UE89NloA4muaq6N .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-9UE89NloA4muaq6N .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-9UE89NloA4muaq6N .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-9UE89NloA4muaq6N .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-9UE89NloA4muaq6N .cluster text{fill:#333;}#mermaid-svg-9UE89NloA4muaq6N .cluster span{color:#333;}#mermaid-svg-9UE89NloA4muaq6N div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-9UE89NloA4muaq6N .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-9UE89NloA4muaq6N rect.text{fill:none;stroke-width:0;}#mermaid-svg-9UE89NloA4muaq6N .icon-shape,#mermaid-svg-9UE89NloA4muaq6N .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-9UE89NloA4muaq6N .icon-shape p,#mermaid-svg-9UE89NloA4muaq6N .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-9UE89NloA4muaq6N .icon-shape .label rect,#mermaid-svg-9UE89NloA4muaq6N .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-9UE89NloA4muaq6N .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-9UE89NloA4muaq6N .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-9UE89NloA4muaq6N :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} push
push
push
push
push
push
不可见页面
首页
分类页
商品列表
商品详情
购物车
结算
订单详情
原生层 detach
内存只保留可见页
状态保留, 返回即恢复


第一步:安装与开启

bash 复制代码
npm install @react-native-ohos/react-native-screens

在 App 入口开启原生屏幕:

tsx 复制代码
import { enableScreens } from '@react-native-ohos/react-native-screens'

enableScreens(true) // 一行开启,全局生效

第二步:配置导航栈

createNativeStackNavigator 替代 createStackNavigator,底层自动走原生屏幕:

tsx 复制代码
import { NavigationContainer } from '@react-navigation/native'
import { createNativeStackNavigator } from '@react-navigation/native-stack'

const Stack = createNativeStackNavigator()

function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator screenOptions={{ headerShown: false }}>
        <Stack.Screen name="Home" component={HomeScreen} />
        <Stack.Screen name="Category" component={CategoryScreen} />
        <Stack.Screen name="ProductList" component={ProductListScreen} />
        <Stack.Screen name="ProductDetail" component={ProductDetailScreen} />
        <Stack.Screen name="Cart" component={CartScreen} />
        <Stack.Screen name="Checkout" component={CheckoutScreen} />
        <Stack.Screen name="OrderDetail" component={OrderDetailScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  )
}

API 和普通 StackNavigator 完全一致 ------navigation.push / navigation.navigate / navigation.goBack 照常调用,开发者无感知。但底层行为变了:

对比 JS StackNavigator Native Stack (screens)
7 层页面内存 全部挂载 只保留可见页
push 动画 JS 线程,掉帧 原生层,60fps
返回恢复 重新渲染 状态已保留
生命周期 模糊 attach/detach 精确

第三步:Tab 冻结------非活跃 Tab 不渲染

底部有 5 个 Tab(首页/分类/购物车/消息/我的),切到首页时其他 4 个 Tab 不该继续渲染:

tsx 复制代码
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'

const Tab = createBottomTabNavigator()

<Tab.Navigator
  screenOptions={{
    // 非活跃 Tab 冻结渲染,保留状态
    freezeOnBlur: true,
  }}
>
  <Tab.Screen name="Home" component={HomeTab} />
  <Tab.Screen name="Category" component={CategoryTab} />
  <Tab.Screen name="Cart" component={CartTab} />
  <Tab.Screen name="Message" component={MessageTab} />
  <Tab.Screen name="Profile" component={ProfileTab} />
</Tab.Navigator>

freezeOnBlur: true 让切走的 Tab 停止渲染但不销毁状态------用户切回来时数据还在,但切走期间不占 GPU 资源。这对"好物优选"的购物车 Tab 特别重要------购物车里有商品列表 + 倒计时,不冻结的话一直在后台跑。


第四步:页面切换动画优化

商品详情页很重(大量图片 + 评论列表),push 时容易卡。原生屏幕的转场动画在原生层执行:

tsx 复制代码
<Stack.Screen
  name="ProductDetail"
  component={ProductDetailScreen}
  options={{
    // 原生层转场动画,不受 JS 线程影响
    animation: 'slide_from_right',
    animationDuration: 300,
    // 透明背景过渡,减少闪烁
    presentation: 'card',
  }}
/>

animation: 'slide_from_right' 在原生层执行------即使 JS 线程在忙(比如图片解码),push 动画也丝滑不卡


为什么"好物优选"选了 Screens?

需求 不开 screens 开启 screens
7 层页面内存 全部挂载 ~200MB 只留可见页 ~60MB
Tab 切换 全部渲染 ✅ freezeOnBlur
push 动画 JS 线程掉帧 ✅ 原生层 60fps
返回恢复 重新渲染 ✅ 状态保留
代码改动 --- ✅ 一行 enableScreens

总结

"好物优选"这个场景里,@react-native-ohos/react-native-screens 解决了三件事:

  1. 内存不炸------7 层页面栈只保留可见页,不可见页原生层 detach
  2. Tab 不浪费 ------freezeOnBlur 让非活跃 Tab 停止渲染
  3. 切换不卡------push/pop 动画在原生层,重页面也不掉帧

如果你也在做多页面导航的 RN 鸿蒙应用(电商、社交、工具类),react-native-screensenableScreens(true) 一行就能收获性能提升的必选基础设施。

相关推荐
lqj_本人12 小时前
Flutter 三方库「flutter_ble_peripheral」的鸿蒙化适配指南
flutter·华为·harmonyos
lqj_本人13 小时前
Flutter 三方库「flutter-dualscreen」的鸿蒙化适配指南
flutter·华为·harmonyos
熊猫钓鱼>_>15 小时前
【SenseNova U1.5 Lite实战】鸿蒙校园工具开发者适配原生统一多模态大模型全记录
人工智能·华为·ai·harmonyos·媒体·sensenova
在人间耕耘16 小时前
鸿蒙7「互动卡片」实测:桌面上多了个“记一笔“按钮 快的很
华为·harmonyos
昇腾知识体系16 小时前
昇腾 AscendC Tiling 设计实战:TilingFunc/TilingData 完整示例与 UB 容量预算
人工智能·华为·知识图谱
RUNIONE17 小时前
合亿RUNIONE 三防平板电脑|手持工业平板 UA810 开源鸿蒙系统,与国产生态深度融合
harmonyos·手持工业平板·手持工业平板厂家
●VON17 小时前
鸿蒙跨平台框架怎么选?从真实需求比较 Flutter、React Native、KMP/CMP 与 Web 路线
flutter·react native·harmonyos
lqj_本人18 小时前
Flutter 三方库「flutter_displaymode」的鸿蒙化适配指南
flutter·华为·harmonyos
邓孟鑫19 小时前
鸿蒙图表MarkerView遮挡解决方案
华为·harmonyos