React Native for OpenHarmony 实战:三方库 react-native-modal-dialog 的鸿蒙化适配指南

发布时间:2026/10/24 2:18:40
React Native for OpenHarmony 实战:三方库 react-native-modal-dialog 的鸿蒙化适配指南 本文记录把react-native-modal-dialog对话框Alert / Confirm / Prompt适配到 HarmonyOS 的完整过程。它做的事提供一个Dialog基类并派生出Alert/Confirm/Prompt三种对话框通过实例方法alert()/confirm()/prompt()弹出来。结论能跑 ——alert()成功切换了内部状态、全屏层也渲染了但本文发现了一个真实的库缺陷hide()方法根本不存在而它的三个默认回调都在调用它。另外这个库踩了ViewPropTypes这个坑RN 0.62 已移除—— 我用扩展 polyfill的方式解决了这正好验证了兼容层可扩展。★★★★★ 一、会崩的地方ViewPropTypes.style以及我如何扩展 polyfillindex.jsL7-L10import{StyleSheet,Dimensions,Text,View,TouchableWithoutFeedback,TextInput,ScrollView,BackHandler,ViewPropTypes,// ★ RN 0.62 已移除这个导出}fromreact-native;constStylePropTypeViewPropTypes.style;// ★ L10模块加载期求值 ⇒ undefined.style ⇒ TypeError⇒库 import 即崩✗修法扩展已有的 polyfill我之前为另一个依赖Text.propTypes.style的库写过一份polyfills/text-prop-types.js。这一轮在同一个文件里加了ViewPropTypes的补齐关键是要覆盖react-native模块上的同名 getterconstPLACEHOLDER_PROP_TYPES{style:{}};// ① Text.propTypesif(!Text.propTypes)Text.propTypes{...PLACEHOLDER_PROP_TYPES};// ② ★ ViewPropTypes 本身RN 0.62 已从 react-native 的导出里移除constRNrequire(react-native);if(!RN.ViewPropTypes){Object.defineProperty(RN,ViewPropTypes,{configurable:true,enumerable:true,get(){return{...PLACEHOLDER_PROP_TYPES};},});}// ③ 顺手补上 View / Image / ScrollView 的 propTypes实测hilog 里 polyfill 自己打的 5 行[polyfill] NOTE | 已为 Text 补回 propTypes供依赖 Text.propTypes.style 的老库使用 [polyfill] NOTE | 已为 react-native 的 ViewPropTypes 补上导出供 ViewPropTypes.style 使用 ← ★ 本轮新增 [polyfill] NOTE | 已为 View 补回 propTypes [polyfill] NOTE | 已为 Image 补回 propTypes [polyfill] NOTE | 已为 ScrollView 补回 propTypes页面判据确认NOTE | ★ RN.ViewPropTypes 是否存在polyfill 后应为 object object PASS | ★★★ polyfill 生效ViewPropTypes 已存在 PASS | ★★★ polyfill 生效ViewPropTypes.style 可取⇒⇒ 库成功 import、页面正常挂载✓✓⇒⇒ 这说明一份 polyfill 可以按需扩展—— 它修的是同一类问题RN 移除的运行时类型声明入口所以遇到新的同类库只要在这个文件里加一段即可 ✓★★★★★ 二、发现一个真实的库缺陷hide()方法不存在Dialog.defaultProps的三个默认回调全都调用this.hide()源码 L35-43staticdefaultProps{posText:OK,onNegClick:function(){this.hide();},// ★onPosClick:function(){this.hide();},// ★onCancel:function(){this.hide();returntrue;},// ★};但Dialog类里没有任何hide方法。实测constinstdlgRef.current;inst.alert(MKD 消息一,{title:MKD 标题一});// ✓ 调用成功inst.hide();// ✗ 抛错NOTE | alert() 调用 ok PASS | ★★★ alert() 之后 state.hidden false已显示 NOTE | hide 抛错 undefined is not a function ← ★★ FAIL | ★★ ref 调用 hide() 不抛错 | 期望true | 实际false实例的 own keys 也印证了props, context, refs, updater, _lockQueue, state, onCancel, params, _reactInternals, _reactInternalInstance⇒没有hidealert是原型方法所以不在 own keys 里但能用⇒ 所以这个库的默认行为是坏的点OKposText⇒ 调onPosClick⇒this.hide()⇒抛错✗点取消negText⇒ 调onNegClick⇒this.hide()⇒抛错✗点遮罩onCancel⇒this.hide()⇒抛错✗使用建议必须自己传onPosClick/onNegClick/onCancel并且在里面用别的方式关闭例如给Dialog传一个自己的hide或者干脆用state受控 —— 但这个库的render()读的是this.params受控改造比较麻烦。⚠️ 这条是静态 运行时双重确认的① 源码里Dialog类没有hide方法定义② 运行时inst.hide抛undefined is not a function③ 实例 own keys 里也没有hide。三点一致 ⇒ 结论可靠 ✓★★★★ 三、继承关系可以精确断言源码L12 / L141 / L150 / L160exportdefaultclassDialogextendsComponent{…}exportclassAlertextendsDialog{…}exportclassConfirmextendsDialog{…}exportclassPromptextendsDialog{…}实测PASS | ★★ Alert 是 classfunction PASS | ★★★ Alert.prototype instanceof Dialog ← 期望true | 实际true PASS | ★★★ Confirm.prototype instanceof Dialog ← 期望true | 实际true PASS | ★★★ Prompt.prototype instanceof Dialog ← 期望true | 实际true⇒X.prototype instanceof Dialog这个断言写法很干净✓比X.super_/Object.getPrototypeOf(X) Dialog更直观static inject四个类都有PASS | ★ Dialog / Alert / Confirm / Prompt 都有 static inject函数★★★ 四、propTypes/defaultProps逐项核对我又把一个数错了NOTE | Dialog.propTypes 的键数 14 NOTE | Dialog.propTypes 的键 buttonBarStyle, buttonStyle, contentStyle, dialogStyle, message, messageStyle, modalStyle, negText, onCancel, onNegClick, onPosClick, posText, title, titleStyle FAIL | ★★ Dialog.propTypes 有 15 项 | 期望15 | 实际14 ← ★ 我数错了 NOTE | Dialog.defaultProps 的键数 4 NOTE | Dialog.defaultProps 的键 onCancel, onNegClick, onPosClick, posText PASS | ★★ Dialog.defaultProps 有 4 项 PASS | ★★ defaultProps.posText OK NOTE | Alert.defaultProps 的键 onCancel, onNegClick, onPosClick, posText, title PASS | ★★ Alert.defaultProps.title Alert PASS | ★★ Alert.defaultProps.posText 继承自 DialogOK ← ★ 展开运算符的继承也验证了 NOTE | Confirm.defaultProps 的键 negText, onCancel, onNegClick, onPosClick, posText, title PASS | ★★ Confirm.defaultProps.title Confirm PASS | ★★ Confirm.defaultProps.negText Cancel NOTE | Prompt.propTypes 的键 onChangeText, placeholder PASS | ★★ Prompt.propTypes 有 2 项 NOTE | Prompt.defaultProps 的键 children, message, negText, onCancel, onNegClick, onPosClick, posText, title PASS | ★★ Prompt.defaultProps.title Prompt / negText Cancel PASS | ★★ Prompt.defaultProps.children 是长度 2 的稀疏数组[,,]⇒Dialog.propTypes实际 14 项我写成 15✗ —— 这是连续第三轮在数量类断言上数错⇒Alert.defaultProps有 5 个键4 个继承 title⇒{...Dialog.defaultProps, title:Alert}展开继承被验证✓★★★ 五、状态机与渲染观察render()开头就很关键L44-47render(){if(this.state.hidden){returnnull;// ★ 初始什么都不渲染}…}实测状态机NOTE | 实例 state 的键 hidden NOTE | 实例 state.hidden true PASS | ★★★ 初始 state.hidden true所以 render 返回 null NOTE | alert 之后 state.hidden false PASS | ★★★ alert() 之后 state.hidden false已显示⇒alert()成功把hidden置为false✓但内容文本没在布局 dump 里观察到⚠️我在alert()之后重新采样 dump含MKD的节点只有我自己页面上的说明文字但找到了两个全屏层w1320 h2115与w1320 h2061这与源码styles.dialog的position:absolute width:window.width height:window.height完全吻合⇒⇒ 结论对话框的全屏容器确实渲染了但它的内容文本title / message / OK 按钮本轮没能在 dump 里定位到⚠️⇒ 我不把文本渲染了写成结论只写容器渲染、内容未观察到 ✓★★ 六、其余预检结论预检项结果dependencies/peerDependencies✅都空老写法九项createClass/React.PropTypes/Text.propTypes/ 字符串 ref /this.refs/mixins/componentWillReceiveProps/componentWillMount/getDefaultProps✅✅全部为空ListView/measure()/onLayout/useNativeDriver/NativeModules/Platform.OS/isRequired✅全空Modal4 处⚠️全是modalStyle/styles.dialogModal这类命名巧合没有真的用Modal本月第四次同类误报唯一真坑ViewPropTypes.style见第一节外部 import只有prop-types/react/react-native✓交付包形态⚠️只有一个index.js7852 B246 行无src/、无.d.ts七、接入与预检要点# 装库无 dependencies、无 peerDependenciesnpminstallgithttps://atomgit.com/oh-react-native/react-native-modal-dialog.git#1.2.3-ohos-1.0.0--ignore-scripts# ★ 还需要在入口最前面引入 polyfill补 Text.propTypes 与 ViewPropTypes否则 import 即崩八、交付包质量与基线说明类别结果交付包内容⚠️只有一个index.js7852 B / 246 行⇒ 没有src/、没有.d.tsspec.json⚠️缺upstreamCommitvalidation⚠️build-pass-device-pending⚠️ 声明的基线reactNative: 0.88.0rnoh: 0.84.4⇒两字段自相矛盾备注库代码零改动改的是我自己的 polyfill关于基线本次验证在RN0.84.1 RNOH0.84.3上完成。⚠️ViewPropTypes与hide()这两条都是版本相关的前者随 RN 版本后者是库自身缺陷⇒ 换基线需重新确认。九、已知限制与本次验证边界9.1 用这个库要知道的事项说明★★★★★hide()不存在但三个默认回调都在调它必须自己传onPosClick/onNegClick/onCancel否则点 OK/取消/遮罩都会抛undefined is not a function★★★★★ 必须补ViewPropTypesL10ViewPropTypes.style在 RN ≥0.62 会抛 TypeError ⇒ import 即崩★★★★render()初始返回nullstate.hidden初始为true⇒ 必须调alert()/confirm()/prompt()才显示★★★ 继承关系可断言Alert.prototype instanceof Dialog等三条全 true★★★Alert.defaultProps是{...Dialog.defaultProps, title}实测 5 个键4 继承 1 title⇒ 展开继承被验证★★Prompt.defaultProps.children是稀疏数组[,,]长度 2不是 0★★props变化不会反映到渲染render()读的是this.params构造时从 props 复制★Modal命中的 4 处是命名巧合modalStyle/styles.dialogModal不是Modal9.2 本次验证的边界★★★ 未能在 dump 里定位到对话框的内容文本title / message / OK 按钮——只确认了全屏容器渲染w1320 h2115与styles.dialog的全屏定义吻合★★★ 未验证confirm()与prompt()的行为只调了alert()★★ 未验证Prompt的TextInput与onChangeText★★ 未验证static inject(ref)的用法只断言它是函数★★ 未验证BackHandlerAndroid 返回键逻辑未验证自定义dialogStyle/modalStyle/contentStyle等 8 个样式 prop未验证Confirm的双按钮布局与negText未在RN 0.88.0/RNOH 0.84.4上复验未测其它屏幕宽度未做跨平台对照。库代码未改动改的是polyfills/text-prop-types.js属于我自己的兼容层。十、常见问题Q1它在 RN 0.84 上能跑吗加 polyfill 之后能跑alert()能把state.hidden从true置为false、全屏容器渲染、继承关系与defaultProps继承都对LogBox无通知。但hide()不存在见 Q2而且内容文本本轮没能在 dump 里定位到。Q2点 OK / 取消会报undefined is not a function因为Dialog.defaultProps里有onNegClick:function(){this.hide();},onPosClick:function(){this.hide();},onCancel:function(){this.hide();returntrue;},而Dialog类里没有hide方法⇒ 这三个默认回调一执行就炸。必须自己传Dialog onPosClick{function () { /* 自己的关闭逻辑 */ }} onNegClick{function () { /* 自己的关闭逻辑 */ }} onCancel{function () { /* 自己的关闭逻辑 */ }} /⚠️ 由于render()读的是this.params构造时快照自己维护一个 hidden 状态这条路不太好走 ⇒比较现实的做法是给Dialog的原型补一个hideimportDialogfromreact-native-modal-dialog;if(typeofDialog.prototype.hide!function){Dialog.prototype.hidefunction(){this.setState({hidden:true});};}Q3一 import 就报Cannot read property style of undefinedindex.jsL10const StylePropType ViewPropTypes.style;而 RN ≥0.62 已移除ViewPropTypes。用 polyfill 把它补上见第一节关键是用Object.defineProperty覆盖react-native模块上的同名 getter。Q4挂了Dialog /却什么都不显示正常——render()第一行就是if (this.state.hidden) return null;而state.hidden初始为true。必须先调实例方法ref.current.alert(消息内容,{title:标题});ref.current.confirm(确认吗);ref.current.prompt(请输入,占位符,textconsole.log(text));Q5怎么确认它真的派生了DialogAlert.prototypeinstanceofDialog;// trueConfirm.prototypeinstanceofDialog;// truePrompt.prototypeinstanceofDialog;// true比看super_或Object.getPrototypeOf直观Q6Prompt的children为什么是[,,]源码里写的是children: [, ,]—— 一个长度 2 的稀疏数组[undefined, undefined]render()里通过children.length 2 children[0] undefined children[1] undefined判断用户没传 children然后自己塞进去一个Text和一个TextInput。实测length 2✓小结react-native-modal-dialog是一个index.js单文件的对话框库DialogAlert/Confirm/Promptdependencies与peerDependencies都为空、老写法九项全空。最值得记下来的是这几条★★★★★ 一个真实的库缺陷hide()不存在但三个默认回调都在调它。静态源码无定义 运行时inst.hide抛undefined is not a function own keys没有hide三重确认✓✓⇒影响点 OK / 取消 / 遮罩的默认行为全部抛错⇒ 必须自己传回调或给原型补一个hide。★★★★★ polyfill 可以按需扩展而且这次扩展得很干净。原来只补Text.propTypes这轮加了ViewPropTypes用Object.defineProperty覆盖react-native模块上的 getterView/Image/ScrollView⇒ hilog 里 5 行[polyfill] NOTE全部打出、页面判据确认ViewPropTypes已是object✓✓⇒这类补丁修的是同一类被移除的运行时类型入口值得放进工程的polyfills/长期保留。★★★★X.prototype instanceof Dialog是断言继承关系最干净的写法三条全 true。★★★★Alert.defaultProps有 5 个键4 个继承 title⇒{...Dialog.defaultProps, title:Alert}的展开继承行为被验证✓★★★ 我又把一个数错了Dialog.propTypes实际 14 项、我写成 15。这是连续第三轮在数量类断言上出错前两次defaultProps项数、forwardRef类型。⇒这次的根因很明确我是手数源码里的字段而不是直接Object.keys(...).length取真值再写期望。⇒改法数量类断言必须先在同一环境里取到真值、再把它作为期望我这一轮其实已经把真值打成了NOTE只是写期望时又凭手数了✓★★★ 全屏容器渲染了、内容文本没观察到要如实区分。我找到了w1320 h2115的全屏层与styles.dialog定义吻合⇒容器确实渲染但没找到title/message/OK文本 ⇒内容只写未观察到不写没渲染✓★★Modal的 4 处命中又是命名巧合modalStyle/styles.dialogModal⇒本月第四次名字里含已移除 API的误报再次印证要扫真实使用形态。★★render()读的是this.params而不是this.props⇒props 变化不会反映到渲染⇒ 想做受控对话框会比较别扭 ✓本篇用到的库项内容三方库react-native-modal-dialog上游1.2.3的鸿蒙适配版适配仓库https://atomgit.com/oh-react-native/react-native-modal-dialog适配 TAG1.2.3-ohos-1.0.0需要 HAR / 权限 / ohpm都不需要纯 JS库类型对话框Dialog基类 Alert/Confirm/Prompt运行时依赖✅dependencies/peerDependencies都空导出形态默认导出Dialogclass具名Alert/Confirm/Prompt都 extends Dialog⚠️ 必须的额外步骤入口最前面引入 polyfill补Text.propTypes与ViewPropTypes⚠️ 库缺陷hide()不存在但defaultProps的 3 个回调都调它 ⇒ 必须自己传回调或给原型补hide许可证MIT上游仓库https://github.com/zhengxiaoyao0716/react-native-modal-dialog宿主工程RNOH084Demo测试页rnAppKey ModalDialogTestAppnpminstallgithttps://atomgit.com/oh-react-native/react-native-modal-dialog.git#1.2.3-ohos-1.0.0--ignore-scripts// ① polyfill入口最前面见正文第一节import./polyfills/text-prop-types;// 内部同时补 Text.propTypes 与 ViewPropTypes// ② 库缺陷补救给 Dialog 原型补一个 hide可选但强烈建议importDialogfromreact-native-modal-dialog;if(typeofDialog.prototype.hide!function){Dialog.prototype.hidefunction(){this.setState({hidden:true});};}import Dialog, {Alert, Confirm, Prompt} from react-native-modal-dialog; const ref useRef(null); Dialog ref{ref} / // 弹出render 初始返回 null必须调方法 ref.current.alert(消息内容, {title: 标题}); ref.current.confirm(确认执行吗, {title: 确认}); ref.current.prompt(请输入, 占位符, text console.log(text)); // 关闭⚠️ 库本身没有 hide见上面的原型补丁 ref.current.hide(); // ⚠️ Dialog.propTypes 14 项 / defaultProps 4 项posText OK 3 个回调 // ⚠️ Alert/Confirm/Prompt 都 extends DialogAlert.prototype instanceof Dialog true // ⚠️ 默认回调调用 this.hide()而 hide 不存在 ⇒ 不传回调点 OK/取消会抛 undefined is not a function // ⚠️ render 读的是 this.params构造时快照⇒ props 变化不反映# 换页启动测试页 —— force-stop 不能省hdc shell aa force-stop com.rnoh084.demo hdc shell aa start-bcom.rnoh084.demo-aEntryAbility--psrnAppKey ModalDialogTestApp判据的复现方式# ① polyfill 是否把 ViewPropTypes 补上hdc shellhilog -x | grep \[polyfill\]# ⇒ 5 行Text / ViewPropTypes / View / Image / ScrollView# ② 契约 继承 状态机 hide 缺陷hdc shellhilog -x | grep mkd-test|Select-StringPASS|FAIL|SUMMARY|NOTE# ⇒ Alert.prototype instanceof Dialog true# ⇒ 初始 state.hidden truealert() 后 false# ⇒ hide 抛错 undefined is not a function环境搭建本手册的验证环境是React Native for OpenHarmonyRNOH。从零准备开发环境DevEco Studio、HarmonyOS SDK API 26、Node.js、ohpm、hvigorw、模拟器与hdc调试请按 CPF-RN 开发者指南的「环境初始化」操作CPF-RN 开发者指南 · 02-搭建准备 · 环境初始化https://atomgit.com/CPF-RN/docs/blob/main/开发者指南/02-搭建准备/环境初始化.md环境就绪后本次验证使用的具体版本组合见文末「验证环境」一节。验证环境项版本React Native0.84.1React19.2.3RNOHnpm / ohpmreact-native-oh/react-native-harmony/rnoh/react-native-openharmony0.84.3Node.js / npmv24.14.0/11.9.0DevEco Studio26.0.0.621HarmonyOS SDKAPI 2626.0.0.32设备HarmonyOS 7.0.0(26.0.0) Beta2 模拟器Pura X Viewohos-x641320×2232density 3本机状态栏高度117px 39vp宿主依赖✅ 无额外依赖需引入扩展后的 polyfill宿主 HAP 产物entry-default-signed.hap本次构建assembleHap3 分 32 秒⇒ 一次成功打包与构建退出码都检查了验证规模polyfill 5 行日志全打出含 ViewPropTypes契约 17/181 条是我数错继承断言 3/3 命中状态机true → false命中hide()缺陷三重确认全屏容器渲染确认4 张截图互异⚠️基线说明交付包spec.json声明RN 0.88.0 RNOH 0.84.4两字段自相矛盾本次验证在RN 0.84.1 RNOH 0.84.3上完成。⚠️ViewPropTypes与hide()两条都是版本/库自身相关的换基线需重新确认。相关社区与项目地址项目地址React Native 鸿蒙官方社区CPF-RNhttps://atomgit.com/CPF-RNRNOH 框架仓库https://atomgit.com/openharmony-RN/ohos_react_nativeRNOH 三方库使用文档https://atomgit.com/OpenHarmony-RN/usage-docsReact Native for OpenHarmony 组织https://atomgit.com/oh-react-nativeRN 三方库鸿蒙适配清单https://atomgit.com/oh-react-native/rn-ohos-adaptation-overview欢迎加入 CPF-RN 鸿蒙社区https://atomgit.com/CPF-RNReact Native for OpenHarmony 组织https://atomgit.com/oh-react-nativeRN 三方库鸿蒙适配清单https://atomgit.com/oh-react-native/rn-ohos-adaptation-overview

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询