本文记录把 react-native-skeleton-placeholder(骨架屏占位图)适配到 HarmonyOS 的完整过程。

它做的事很专一:把真实内容"骨架化" —— 递归遍历 children,把每个带文字/叶子的节点替换成灰块,再用一层渐变高光在这些灰块上扫过,形成"加载中"的观感。

结论:组件本体可以跑,三种渲染分支都验证到了;但 shimmer 的高光层(LinearGradient)一次都没有渲染 —— 这是一个已钉死的现象。
另外它有两个原生 peer 依赖,本文会把"它们的鸿蒙适配版是否存在"和"我为什么选择打桩"都写清楚。

★★★★★ 一、两个原生 peer 依赖:都存在,但我选择了打桩

库的 package.json:

"peerDependencies": {
  "react": ">=0.14.8",
  "react-native": ">=0.50.1",
  "react-native-linear-gradient": "^2.5.6",
  "@react-native-masked-view/masked-view": "^0.2.8"
}

而源码里它们是无条件 require 的(lib/skeleton-placeholder.js L36 / L39):

const masked_view_1 = __importDefault(require("@react-native-masked-view/masked-view"));
const react_native_linear_gradient_1 = __importDefault(require("react-native-linear-gradient"));

⇒ 两个都必须能被解析(否则打包失败),而它们都是原生库。

它们的鸿蒙适配版都存在 ✓:

上游鸿蒙适配版
react-native-linear-gradient@2.8.3@react-native-ohos/react-native-linear-gradient@3.2.0 ✓(⚠️ 版本与 peer 的 ^2.5.6 不一致)
@react-native-masked-view/masked-view@0.3.2@react-native-ohos/masked-view@0.4.3 ✓(⚠️ 包名不同,需 metro 映射)

但我这一轮选择打桩隔离,理由是风险已知:HAR 接入此前实测失败过一次 ——

hvigor ERROR: Error Code: 00308018 Unknown Error
hvigor BUILD FAILED in 2 s 540 ms        ← 只 2.5 秒 ⇒ 配置/解析期错误

⇒ 不在这一轮同时赌两个 HAR ✓ ⇒ 代价:shimmer 的渐变效果不可见(这一代价后来变成了本轮最有价值的发现,见第四节)。

★★★★ 桩的设计:带调用计数

// stubs/react-native-masked-view.js
let renderCount = 0;
const MaskedView = (props) => {
  renderCount += 1;
  console.log(`[masked-view-stub] NOTE | MaskedView 被渲染(累计 ${renderCount} 次)…`);
  const {children, maskElement, style, ...rest} = props;
  return <View {...rest} style={style}>
    <View testID="masked-view-stub-mask">{maskElement}</View>      {/* 骨架块 */}
    <View testID="masked-view-stub-content">{children}</View>       {/* 底色 + 渐变 */}
  </View>;
};

linear-gradient 的桩同理(并会打印它收到的 colors / start / end)。

⇒ 这样一个"空桩"就变成了判据:它被渲染几次,就能反推组件的分支走到了哪里 ✓(见第三节)

★★★★★ 二、源码的三段渲染逻辑(这是理解一切的关键)

const [layout, setLayout] = React.useState();
const isAnimationReady = Boolean(speed && layout?.width && layout?.height);

if (!enabled || !placeholders) return children;                        // ① 关闭 ⇒ 直接返回 children
if (!layout?.width || !layout?.height)
  return <View onLayout={(e) => setLayout(e.nativeEvent.layout)}>{placeholders}</View>;   // ② 未就绪 ⇒ 纯 View
return (<MaskedView style={{height: layout.height, width: layout.width}} maskElement={placeholders}>
  <View style={[StyleSheet.absoluteFill, {backgroundColor}]} />
  {isAnimationReady && highlightColor !== undefined && transparentColor !== undefined && (
    <Animated.View style={animatedGradientStyle}>
      <LinearGradient colors={[transparentColor, highlightColor, transparentColor]} … />
    </Animated.View>
  )}
</MaskedView>);                                                          // ③ 就绪 ⇒ MaskedView + 渐变

⇒ 三段分支非常清晰:

  • ① enabled=false ⇒ 原样渲染 children
  • ② onLayout 未就绪 ⇒ 先用纯 View 占位,同时靠 onLayout 量自己的宽高
  • ③ 就绪 ⇒ MaskedView(遮罩=骨架块)+ 底色层 + shimmer 渐变层

★★★★★ 三、三段分支 + layout 链路全部验证到(桩计数是功臣)

实测(三个实例:S1 两个 Item、S2 嵌套 Item、S3 enabled={false}):

NOTE | ★ MaskedView 桩渲染次数 = 2
NOTE | ★ LinearGradient 桩渲染次数 = 0          ← ★ 见第四节

桩的渲染日志:

[masked-view-stub] NOTE | MaskedView 被渲染(累计 1 次)—— 说明 layout 已就绪、走到了 MaskedView 分支
[masked-view-stub] NOTE | MaskedView 被渲染(累计 2 次)…

⇒ 恰好 2 次 = S1 + S2(S3 是 enabled=false ⇒ 走分支① ⇒ 不渲染 MaskedView ✓)
⇒ ⇒ 一段桩计数,同时验证了"分支① 被短路"和"分支②→③ 的迁移发生了 2 次" ✓✓

再看 layout 是否真的正确 —— 我的桩把 style={{height: layout.height, width: layout.width}} 原样透传,所以从 dump 就能读到 layout:

Custom#masked-view-stub [54,570,1266,798]      ⇒  1212 × 228
Custom#masked-view-stub [54,955,1266,1315]     ⇒  1212 × 360

对照 S1 的构成:两个 Item 是 height=40 + height=24 + marginTop=12
⇒ 40 + 24 + 12 = 76vp ⇒ 76 × 3 = 228px ⇒ 与第一个 MaskedView 的 h=228 精确一致 ✓✓
对照 S2:外层 Item height=120 ⇒ 120 × 3 = 360px ⇒ 与第二个 h=360 精确一致 ✓✓

⇒ ⇒ "onLayout 量到了正确的宽高 + transformToPlaceholder 的尺寸传递正确"这两个环节,用两个独立数字闭环验证了 ✓✓
⇒ (顺带说明:onLayout 在 RNOH 上是可靠的,这也再次印证了"该用 onLayout、不该用 measure()")

★★★★★ 四、核心发现:MaskedView 渲染了,但 shimmer 的 LinearGradient 一次都没渲染

NOTE | ★ MaskedView 桩渲染次数 = 2
NOTE | ★ LinearGradient 桩渲染次数 = 0
FAIL | ★★★ LinearGradient 桩被渲染 ⇒ shimmer 分支条件全部成立(>0) | 期望=true | 实际=false

把条件逐项推理一遍(渲染分支③的条件是 isAnimationReady && highlightColor !== undefined && transparentColor !== undefined):

条件推理结论
speed默认 800(未传)✅ 真
layout.width / layout.height上面已量到 1212 × 228,两者都 > 0✅ 真
⇒ isAnimationReadyBoolean(800 && 1212 && 228)✅ 应为真
highlightColor默认 '#F2F8FC'✅ 非 undefined
transparentColorgetTransparentColor('#F2F8FC') ⇒ '#F2F8FC00'✅ 非 undefined

⇒ ⇒ 三个条件按推理都应成立,但 LinearGradient 就是没渲染 ✗

能确定的位置:问题不在 layout 链路(已闭环验证),也不在颜色解析(否则整个组件会抛错、而组件渲染正常),
所以收敛到"<Animated.View style={animatedGradientStyle}> 这一层":

// animatedGradientStyle = {...absoluteFillObject, flexDirection:'row',
//   transform:[{translateX: animatedValueRef.current.interpolate({inputRange:[0,1], outputRange:[-w, w]})}]}
// 动画:Animated.loop(Animated.timing(v, {toValue:1, duration:speed, easing:Easing.ease, useNativeDriver: true}))

⇒ useNativeDriver: true 是这一层最可疑的地方 —— 它驱动的是 translateX(transform,本来是可以原生驱动的)✓
⇒ ⇒ 但在这套 RNOH 上,"原生驱动 + Animated.loop + interpolate"这个组合是否让子树的渲染被跳过,本轮没有直接证据 ⚠️
⇒ 如实记为:现象已钉死(LinearGradient 0 次)、根因收敛到 Animated.View 那一层、未最终确认。

⚠️ 这一节也说明了一个诚实的局限:打桩能验证"结构与分支",但验证不了"被桩替换掉的那层效果"。
而恰恰是"渐变层"出了问题 —— 如果我一开始就接了 HAR,可能会更早看到它(也可能更早被 HAR 的坑卡住)。两条路各有取舍 ✓

★★★ 五、骨架块几何:Item 的 width/height 直接变成块尺寸

实测(dump 里的真实块):

实例Item 的 props预言(density 3)实测
S1 第 1 个width=200 height=40600 × 120px✅ w=600 h=120
S2 外层width=260 height=120— / 360px✅ h=360(宽度是满宽:容器分支没有固定宽度)
S3(enabled=false)真实内容 200×40600 × 120px✅ w=600 + 文本「真实内容 200x40」

⇒ Item 的 height 精确生效 ✓
⇒ width 只在"叶子块"上生效(S1 第 1 个 = 600px ✓);有子节点的"容器块"宽度会被父容器拉满(S2 外层 = 1212px)——
这与源码一致:容器走 styles.placeholderContainer(只有 backgroundColor:'transparent',没有固定宽度)✓

enabled={false} 的 A/B 也很干净:找到文本 「真实内容 200x40」 ✓ ⇒ 说明它走的是分支①(直接返回 children),没有被骨架化 ✓

★★ 六、契约与其余预检

契约(全 PASS):

NOTE | 默认导出的 typeof = function
PASS | ★ 默认导出是函数组件(function)
PASS | ★★ 带静态属性 Item(库的复合组件写法)
NOTE | Item.displayName = SkeletonPlaceholderItem
PASS | ★★ Item.displayName = 'SkeletonPlaceholderItem'
PASS | ★ 是函数组件(无 prototype.render)

⇒ SkeletonPlaceholder.Item 是"函数组件上挂静态子组件"的写法 ⇒ 所以判定它"是不是组件"要同时看函数和静态属性 ✓

其余预检:

预检项结果
老写法九项✅✅ 全部为空
Platform.OS✅ 空
measure() / measureInWindow✅ 空(用的是 onLayout)
onLayout1 处 —— RNOH 上可靠,本轮已闭环验证 ✓
useNativeDriver1 处 true(驱动 translateX/transform ⇒ 用法本身正确)
NativeModules / requireNativeComponent✅ 空(原生能力在 peer 里)
Dimensions模块顶层读 window.width = 440 ✓
prepack✅ npm install 不跑

一条 React 警告(非崩溃):

"{}: `key` is not a prop. Trying to access it will result in `undefined` being returned…"

⇒ 与库的 transformToPlaceholder 里 <View key={index} … children={…} /> 这种写法有关(把 children 当 prop 传)⇒ 只是警告 ✓

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


七、接入与预检(要点)

# ① 装库
npm install "git+https://atomgit.com/oh-react-native/react-native-skeleton-placeholder.git#5.2.4-ohos-1.0.0" --ignore-scripts

# ② 它的两个原生 peer —— 二选一:
#    (A) 接真库(功能完整,但两个 HAR 都要接)
npm install --ignore-scripts react-native-linear-gradient @react-native-masked-view/masked-view
#        + 在 oh-package.json5 里声明:
#          @react-native-ohos/react-native-linear-gradient  → node_modules/.../harmony/*.har
#          @react-native-ohos/masked-view                   → node_modules/.../harmony/*.har
#    (B) 打桩隔离(零原生接线,代价:shimmer 不可见)—— 本文采用
#        metro.config.js 的 resolver.extraNodeModules:
#          '@react-native-masked-view/masked-view': <stub>
#          'react-native-linear-gradient':          <stub>

八、交付包质量与基线说明

类别结果
交付包内容只有 lib/(skeleton-placeholder.js 9796 B + .d.ts)⇒ 可读但无 src/ ⚠️
spec.json⚠️ 缺 upstreamCommit
validation⚠️ "build-pass-device-pending"
⚠️ 声明的基线reactNative: "0.88.0" + rnoh: "0.84.4" ⇒ 两字段自相矛盾
⚠️ 许可证GitHub 记 MIT、npm 与交付包记 ISC —— 不一致
备注实现零改动(本轮未修改库任何文件)

关于基线:本次验证在 RN 0.84.1 + RNOH 0.84.3 上完成。库无已移除写法 ⇒ 契约结论跨基线成立;
但第四节的 shimmer 问题与 Animated 的原生驱动有关,换基线时值得复验。


九、已知限制与本次验证边界

9.1 用这个库要知道的

事项说明
★★★★ 两个原生 peer:react-native-linear-gradient + @react-native-masked-view/masked-view都要能被解析;鸿蒙适配版分别是 @react-native-ohos/react-native-linear-gradient@3.2.0 与 @react-native-ohos/masked-view@0.4.3
★★★★ 在 RNOH 上 shimmer 高光层没有渲染LinearGradient 桩渲染 0 次 ⇒ 只剩底色层;(本次用桩验证,根因收敛到 Animated.View 层)
★★★ 三段渲染分支enabled=false ⇒ 原样 children;onLayout 未就绪 ⇒ 纯 View;就绪 ⇒ MaskedView
★★★ 骨架块尺寸 = Item 的 propsItem 是叶子 ⇒ width/height 都生效;Item 有子节点 ⇒ 宽度被父容器拉满
★★★ onLayout 链路可靠实测 layout.height 与子项之和精确一致(228 = 76vp×3;360 = 120vp×3)
★★ 会有一条 key is not a prop 的 React 警告库把 children 当 prop 传导致,仅警告
★ Item.displayName = 'SkeletonPlaceholderItem'可断言的契约

9.2 本次验证的边界

  1. ★★★ shimmer 高光效果【未验证】(LinearGradient 用桩替换,且实测桩 0 次渲染 ⇒ 渐变这一层完全没看过);
  2. ★★★ 没有接真 HAR(两个原生库的鸿蒙适配版存在但未接入)⇒ "接了 HAR 之后 shimmer 是否就正常"未知;
  3. 未验证 speed / direction / shimmerWidth / highlightColor 各取值的实际效果;
  4. 未验证 borderRadius 的圆角效果(dump 不反映);
  5. 未验证 更深的嵌套(3 层以上)与 Fragment children;
  6. 未验证 children 是字符串/数组时的骨架化结果;
  7. 未验证 Item 的 style 与零散 props 混合时的优先级(只用了零散 props);
  8. 未验证 多实例同时存在时的性能与 Animated.loop 行为;
  9. 未在 RN 0.88.0 / RNOH 0.84.4 上复验;
  10. 未测其它屏幕宽度;未做跨平台对照。

未改动库代码。


十、常见问题

Q1:它在 RN 0.84 上能跑吗?

组件本体能跑:三段渲染分支都验证到(enabled=false 原样渲染 ✓、onLayout 链路 ✓、MaskedView 分支走了 2 次 ✓),
骨架块几何精确(Item 200×40 ⇒ 600×120px)。
但 shimmer 的高光渐变层没有渲染(见第四节)。

Q2:npm install 报 Unable to resolve module @react-native-masked-view/masked-view?

它和 react-native-linear-gradient 是两个原生 peer,必须能被解析。两条路:
接真库(@react-native-ohos/masked-view + @react-native-ohos/react-native-linear-gradient + HAR),
或者在 metro 里给它们指向空桩(本文采用,代价是 shimmer 不可见)。

Q3:为什么骨架块出来了,但没有"扫过去的高光"?

在本次(打桩)环境下,LinearGradient 的渲染次数是 0 —— 也就是根本没渲染高光层。
按源码推断,isAnimationReady(依赖 layout)与颜色条件都应成立,所以问题收敛到
<Animated.View style={…translateX 插值…}> 这一层(它用的是 useNativeDriver: true)。
建议:接上真 HAR 后复验;若仍无高光,可试着把该动画改成 useNativeDriver: false 观察。

Q4:onLayout 在 RNOH 上可靠吗?

可靠。 本轮用它做了闭环验证:MaskedView 的 style 用的就是 layout 的宽高,
实测 228px = (40+24+12)vp × 3、360px = 120vp × 3,两组都精确一致 ✓
(对照:用 measure() 量布局在 RNOH 上拿不到值 —— 这个库选 onLayout 是对的。)

Q5:enabled={false} 有什么用?

用来"临时关掉骨架屏、直接显示真实内容",常用于数据加载完成后切换。
实测它会让组件直接返回 children(不再走骨架化,也不渲染 MaskedView)✓

Q6:怎么让骨架块有圆角?

Item 上的零散 props 会被当作样式:<SkeletonPlaceholder.Item width={200} height={40} borderRadius={8} />
⇒ getItemStyle 会把非 children/style 的 props 当样式对象 ✓

Q7:为什么控制台有 key is not a prop 的警告?

库内部把 children 当 prop 传给 View(<View key={index} … children={…} />)⇒ React 会警告。
仅警告,不影响功能。


小结

react-native-skeleton-placeholder 是函数组件 + 静态 Item 子组件的骨架屏库,
三段渲染分支清晰(enabled=false / onLayout 未就绪 / 就绪后 MaskedView),九项老写法全空。

最值得记下来的是这几条:

  1. ★★★★★ 两个原生 peer 依赖,但"打桩 + 计数"能验证出很多。
    react-native-linear-gradient 与 @react-native-masked-view/masked-view 都是原生库
    (鸿蒙适配版 @react-native-ohos/react-native-linear-gradient@3.2.0 / @react-native-ohos/masked-view@0.4.3 都存在);
    我给它们打了带调用计数的桩 ⇒ 计数直接反推了"分支走到了哪一步" ✓

  2. ★★★★★ 一段桩计数验证了两件事:MaskedView 渲染 2 次 = S1 + S2 ✓,
    而 S3(enabled=false)一次也没渲染 ✓ ⇒ 分支①被短路 + 分支②→③迁移两次,一次拿到 ✓

  3. ★★★★★ onLayout 链路做了闭环验证。
    桩原样透传 style={{height: layout.height, width: layout.width}} ⇒ dump 读到 228 / 360
    ⇒ 与 (40+24+12)vp×3、120vp×3 精确相等 ✓✓
    ⇒ "onLayout 量的值"与"子项尺寸之和"互相印证 ✓

  4. ★★★★★ 一个已钉死的适配问题:LinearGradient 渲染 0 次。
    MaskedView 渲染了、layout 完全正确、颜色解析不会抛错 ⇒ 条件按推理都该成立,但高光层没渲染 ⇒
    根因收敛到 <Animated.View>(useNativeDriver: true + translateX 插值)那一层 —— 未最终确认,如实标注 ✓

  5. ★★★ 骨架块尺寸规则:Item 是叶子 ⇒ width/height 都生效(200×40 ⇒ 600×120px ✓);
    Item 有子节点 ⇒ 宽度被父容器拉满(走 placeholderContainer,没有固定宽度)✓

  6. ★★★ 一个诚实的局限:打桩能验证"结构与分支",验证不了"被替换掉的那层效果" ——
    而恰恰是渐变层出了问题。若一开始接 HAR 可能更早看到它(也可能更早被 HAR 的坑卡住)。两条路各有取舍 ✓

  7. ★★ 复合组件的契约写法:SkeletonPlaceholder.Item 是"函数组件 + 静态属性" ⇒
    断言要同时看函数与**Item.displayName** ✓

  8. ⚠️ 我自己的两处问题:
    ① PowerShell 里写了 if ($w==0) {} 这种非法语句 ⇒ 刷了一屏报错(但结论没受影响);
    ② 截图重拍三次才拿到 4/4 —— 因为"滚到底之后画面就不再变化"⇒ 应该先规划好四个不同的位置/状态再拍 ✓


本篇用到的库

项内容
三方库react-native-skeleton-placeholder(上游 5.2.4 的鸿蒙适配版)
适配仓库https://atomgit.com/oh-react-native/react-native-skeleton-placeholder
适配 TAG5.2.4-ohos-1.0.0
需要 HAR / 权限 / ohpm⚠️ 两个原生 peer 需要:@react-native-ohos/react-native-linear-gradient / @react-native-ohos/masked-view(本轮打桩未接)
库类型骨架屏占位(骨架化 children + shimmer 高光)
运行时依赖✅ 无 dependencies;⚠️ 两个原生 peer(见上)
prepack / postinstall✅ 没有会阻塞安装的脚本
许可证ISC(GitHub 记 MIT,不一致)
上游仓库https://github.com/chramos/react-native-skeleton-placeholder(★733)
宿主工程RNOH084Demo(测试页 rnAppKey = SkeletonPlaceholderTestApp)
# 装库
npm install "git+https://atomgit.com/oh-react-native/react-native-skeleton-placeholder.git#5.2.4-ohos-1.0.0" --ignore-scripts
# 两个原生 peer 二选一:
#   (A) 接真库:npm install react-native-linear-gradient @react-native-masked-view/masked-view
#       + 在 oh-package.json5 里声明 @react-native-ohos/react-native-linear-gradient 与 @react-native-ohos/masked-view 的 HAR
#   (B) 打桩:metro 的 resolver.extraNodeModules 指向空桩(本文采用)
import SkeletonPlaceholder from 'react-native-skeleton-placeholder';

// ① 基本用法:把真实结构"骨架化"
<SkeletonPlaceholder>
  <SkeletonPlaceholder.Item width={200} height={40} borderRadius={8} />
  <SkeletonPlaceholder.Item width={300} height={24} borderRadius={4} marginTop={12} />
</SkeletonPlaceholder>

// ② 嵌套:外层是容器(宽度会被拉满),内层是叶子
<SkeletonPlaceholder>
  <SkeletonPlaceholder.Item width={260} height={120} borderRadius={12}>
    <SkeletonPlaceholder.Item width={120} height={24} borderRadius={6} />
  </SkeletonPlaceholder.Item>
</SkeletonPlaceholder>

// ③ 关掉骨架屏:直接显示真实内容
<SkeletonPlaceholder enabled={false}>
  <MyRealContent />
</SkeletonPlaceholder>

// ⚠️ 两个原生 peer 必须能被解析(接 HAR 或打桩)
// ⚠️ 在 RNOH 上 shimmer 的高光层实测没有渲染(LinearGradient 桩 0 次)
// ⚠️ Item 有子节点时宽度会被父容器拉满;叶子节点 width/height 都生效
// ⚠️ 会有 'key' is not a prop 的 React 警告(库内部把 children 当 prop 传)
# 换页启动测试页 —— force-stop 不能省
hdc shell aa force-stop com.rnoh084.demo
hdc shell aa start -b com.rnoh084.demo -a EntryAbility --ps rnAppKey SkeletonPlaceholderTestApp

判据的复现方式

# ① 契约 + 桩计数:逐条 PASS/FAIL 日志
hdc shell "hilog -x | grep skp-test" | Select-String 'PASS|FAIL|SUMMARY|NOTE'
#    ⇒ Item.displayName、MaskedView 渲染次数、LinearGradient 渲染次数
# ② 桩自己的渲染日志(每次渲染都会打一行)
hdc shell "hilog -x | grep -e masked-view-stub -e linear-gradient-stub"
# ③ 骨架块几何 + layout 闭环
devecocli ui layout | Select-String 'masked-view-stub'
#    ⇒ 第一个 stubs 的 box 高 228(= (40+24+12)vp×3)、第二个 360(= 120vp×3)
# ④ enabled=false 的对照:dump 里应出现真实内容文本
devecocli ui layout | Select-String '真实内容'

验证环境

项版本
React Native0.84.1
React19.2.3
RNOH(npm / ohpm)@react-native-oh/react-native-harmony / @rnoh/react-native-openharmony 0.84.3
Node.js / npmv24.14.0 / 11.9.0
DevEco Studio26.0.0.621
HarmonyOS SDKAPI 26(26.0.0.32)
设备HarmonyOS 7.0.0(26.0.0) Beta2 模拟器 Pura X View(ohos-x64),1320×2232,density 3
本机状态栏高度117px = 39vp
宿主依赖⚠️ 两个原生 peer 用带计数的空桩隔离
宿主 HAP 产物entry-default-signed.hap
本次构建assembleHap 3 分 50 秒 ⇒ 一次成功(打包与构建退出码都检查了)
验证规模契约 8 条全 PASS;桩计数闭环(MaskedView 2 次 / LinearGradient 0 次);layout 双数字闭环(228 / 360 精确);骨架块几何命中(600×120);enabled=false 对照成立;4 张截图互异

⚠️ 基线说明:交付包 spec.json 声明 RN 0.88.0 + RNOH 0.84.4(两字段自相矛盾),本次验证在 RN 0.84.1 + RNOH 0.84.3 上完成。
契约类结论跨基线成立;shimmer 未渲染这一条与 Animated 原生驱动有关,换基线时值得复验。


相关社区与项目地址

项目地址
React Native 鸿蒙官方社区(CPF-RN)https://atomgit.com/CPF-RN
RNOH 框架仓库https://atomgit.com/openharmony-RN/ohos_react_native
RNOH 三方库使用文档https://atomgit.com/OpenHarmony-RN/usage-docs
React Native for OpenHarmony 组织https://atomgit.com/oh-react-native
RN 三方库鸿蒙适配清单https://atomgit.com/oh-react-native/rn-ohos-adaptation-overview

欢迎加入 CPF-RN 鸿蒙社区:https://atomgit.com/CPF-RN

React Native for OpenHarmony 组织:https://atomgit.com/oh-react-native

RN 三方库鸿蒙适配清单:https://atomgit.com/oh-react-native/rn-ohos-adaptation-overview

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐