首页 / 资讯中心 / 文章详情

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

React Native for OpenHarmony 实战:三方库 react-native-simple-table 的鸿蒙化适配指南 ★ FEATURED ARTICLE
本文记录把react-native-simple-table极简表格适配到 HarmonyOS 的完整过程。它做的事用横向ScrollView 表头 纵向ScrollView拼出一个表格列由columns含title/dataIndex/width定义行由dataSource提供。结论可用。而且这是这几轮里代码量最小的一个库 —— 只有index.js105 Bsrc/Table.js3282 B / 137 行两个源文件零依赖。判据结果是12 PASS / 2 FAIL而那 2 条 FAIL是我自己的断言方法错详见第五节propTypes.X.isRequired在运行时根本不可检测—— 它是选了isRequired版本的 validator 函数而这个函数上并没有.isRequired属性。★★★★★ 一、预检至今最轻的一个库预检项结果老写法九项createClass/React.PropTypes/ViewPropTypes/Text.propTypes/ 字符串 ref /this.refs/mixins/componentWillReceiveProps/componentWillMount/getDefaultProps✅✅全部为空ListView.DataSource/ListView✅ 空measure()/onLayout/useNativeDriver/NativeModules/Modal/Animated/FlatList✅全部为空Platform.OS✅空零平台分支createClass✅精确命中 0、裸词也 0dependencies/peerDependencies✅✅都是空⇒零依赖外部 import只有reactprop-types✓isRequired4 处⚠️ 全在propTypes里L21/L22/L24/L27⇒ 只是类型校验不崩 ✓ScrollView5 处✓它就是用 ScrollView 拼的scripts只有test⇒ 没有prepare不需要--ignore-scripts规模只有index.jssrc/Table.jssrc/Table.js3282 B / 137 行index.js105 Bimport Table from ./src/Tableexport default Table⇒只有默认导出★★★★★ 二、Table是 class —— 这次按 class 断言一次全中先看源码那一行坑 327 的固定动作// src/Table.js L17classTableextendsComponent{// src/Table.js L137exportdefaultTable实测NOTE | 默认导出 Table 的 typeof function PASS | ★★★ Table 是 classfunction NOTE | Table 有 prototype.render function PASS | ★★★ Table 有 prototype.render它是 class 组件 PASS | ★★ 入口没有具名的 Table 导出⇒⇒ 这次是 class所以断言prototype.render是 function✓另两种形态是forwardRef与函数组件判据不同判别三档现在每次都先查这个写法typeofprototype.render判据class X extends Componentfunctionfunction断言有prototype.renderconst X ({…}) …functionundefined断言语没有prototype.renderX React.forwardRef(…)objectundefined断言$$typeof Symbol(react.forward_ref)★★★★★ 三、propTypes/defaultProps清单比对 精确值全中源码classTableextendsComponent{staticpropTypes{columns:PropTypes.arrayOf(PropTypes.shape({title:PropTypes.string.isRequired,dataIndex:PropTypes.string.isRequired,width:PropTypes.number,})).isRequired,columnWidth:PropTypes.number,height:PropTypes.number,dataSource:PropTypes.array.isRequired,renderCell:PropTypes.func,};staticdefaultProps{columns:[],dataSource:[],columnWidth:DEFAULT_COLUMN_WIDTH,// 60height:DEFAULT_HEIGHT,// 240renderCell:undefined,};…}实测清单比对 精确值NOTE | propTypes 的键数 5 NOTE | propTypes 的键 columnWidth, columns, dataSource, height, renderCell PASS | ★★★ propTypes 清单 [columns, columnWidth, dataSource, height, renderCell] NOTE | defaultProps 的键数 5 NOTE | defaultProps 的键 columnWidth, columns, dataSource, height, renderCell PASS | ★★★ defaultProps 清单 [columns, columnWidth, dataSource, height, renderCell] NOTE | defaultProps.columnWidth 60 PASS | ★★★ defaultProps.columnWidth 60DEFAULT_COLUMN_WIDTH NOTE | defaultProps.height 240 PASS | ★★★ defaultProps.height 240DEFAULT_HEIGHT PASS | ★★ defaultProps.columns 是空数组 PASS | ★★ defaultProps.dataSource 是空数组 PASS | ★★ defaultProps.renderCell undefined⇒⇒defaultProps8 条全 PASS清单一致 60/240/ 两个空数组 /undefined✓✓⇒60与240是从源码常量DEFAULT_COLUMN_WIDTH/DEFAULT_HEIGHT抄的不是猜的✓★★★★★ 四、4 个方法全在prototype上含 3 个_前缀私有方法源码里这些方法都是普通方法写法_xxx() {}_renderCell(cellData,col){…}_renderHeader(){…}_renderRow(rowData,index){…}render(){…}实测NOTE | prototype 上缺失的方法 (无) PASS | ★★★ 4 个方法都在 prototype 上含 3 个 _ 前缀私有方法⇒⇒ 这次是原型方法档与箭头类字段只在实例上那一档形成对照✓★★★★★ 五、2 条 FAIL 是我的断言方法错propTypes.X.isRequired不可运行时检测我写了两条断言check(★★ propTypes.dataSource 是 isRequired,true,!!T.propTypes?.dataSource?.isRequired);check(★★ propTypes.columns 是 isRequired,true,!!T.propTypes?.columns?.isRequired);实测NOTE | propTypes.dataSource 是否 isRequired false FAIL | ★★ propTypes.dataSource 是 isRequired | 期望true | 实际false FAIL | ★★ propTypes.columns 是 isRequired | 期望true | 实际false但源码里明明写了.isRequiredL24 / L27。于是我单独验证了prop-types本身的机制string.isRequired 的 typeof function string.isRequired.isRequired undefined string.isRequired 有没有 isRequired 属性 false String(P.string) function () { [native code] } String(P.string.isRequired) function () { [native code] }⇒⇒PropTypes.X.isRequired是一个validator 函数isRequired版本的校验器这个函数上并没有.isRequired这个属性✗⇒⇒ 所以!!propTypes.dataSource.isRequired永远是false——我的断言在原理上就不可能通过✓这意味着想验证的东西可行的做法不可行的做法“这个 prop 是必填”读源码唯一可靠、或缺参时看 LogBox 是否警告❌!!propTypes.X.isRequired“这个 prop 有校验器”typeof propTypes.X function❌两种版本都是 function区分不了⇒⇒ 教训isRequired是在声明时选用了 isRequired 版本的 validator一旦拿到propTypes.X就无法再判断它当初是不是 isRequired 版本** ——因为String()两边都是function () { [native code] }也没有任何可读标记。⇒⇒ 这是本轮最有价值的技术发现也是我这一轮唯一的两条 FAIL都是同一个原因。★★★★★ 六、渲染证据7 处文本命中 行高间隔一致页面里放了两个表格E13 列 × 3 行列宽120 / 80 / 100height{300}E22 列 × 2 行不传columnWidth与height⇒ 用默认的60 / 240布局 dump 实测E1✓ 「STB 名称」 w171 h49 x141 y1220 ✓ 「STB 数量」 w171 h49 x441 y1220 ✓ 「STB 备注」 w171 h49 x711 y1220 ✓ 「苹果」 w85 h49 x184 y1303 ✓ 「香蕉」 w85 h49 x184 y1381 ✓ 「樱桃」 w85 h49 x184 y1459 ✓ 「红富士」 w127 h49 x733 y1303 ⇒ 命中 7 / 9从这些数字能读出三件事✓✓观察结论三列表头的y都是 1220、x 141 / 441 / 711表头横向排列在同一个行上✓x递增、y相同 ⇒ 是一行三格而不是三行)三行数据的y 1303 / 1381 / 1459y间隔恰好 781381−130378、1459−138178⇒行高一致、逐行排布无重叠✓所有h都是 49单元格高度统一 ✓数据格x184与表头x141不同表头与数据是两套ViewheaderItem与cell两者minHeight分别是 30 与 25⇒ 内容居中位置略有差异 ✓⇒⇒ 这比文本存在强得多它证明表格是表头一行 数据多行的正确结构而不是一堆文本堆在一起 ✓⚠️ 「STB 键」/「STB 值」E2 的表头没在首屏 dump 里命中 —— 它们在页面更下方需要滚动。本轮的采样点在第一屏所以记未观察到在更下方。★★ 七、其余预检结论预检项结果交付包内容index.js105 Bsrc/Table.js3282 B / 137 行.idea/IDE 配置无害screenshots/screenshot.png151 KB样式精确值headerItem.minHeight30/cell.minHeight25/row.backgroundColor#fbfbfb/borderRightColor#dfdfdfScrollView用法外层horizontal{true} 内层纵向 ⇒ 双向滚动许可证Apache-2.0不是 MIT八、接入与预检要点# 零依赖dependencies 与 peerDependencies 都空也没有 prepare 脚本npminstallgithttps://atomgit.com/oh-react-native/react-native-simple-table.git#0.0.3-ohos-1.0.0--ignore-scripts九、交付包质量与基线说明类别结果交付包内容index.js105 Bsrc/Table.js3282 B只有 2 个源文件spec.json⚠️缺upstreamCommitvalidation⚠️build-pass-device-pending⚠️ 声明的基线reactNative: 0.88.0rnoh: 0.84.4⇒两字段自相矛盾备注库代码零改动关于基线本次验证在RN0.84.1 RNOH0.84.3上完成。本库零依赖、零平台分支、零原生代码、useNativeDriver零命中⇒结论跨基线成立✓十、已知限制与本次验证边界10.1 用这个库要知道的事项说明★★★★★Table是 classtypeof是function、prototype.render是 function4 个方法_renderCell/_renderHeader/_renderRow/render全在prototype上★★★★★defaultProps5 项、值精确columns: []/dataSource: []/columnWidth: 60/height: 240/renderCell: undefined★★★★★propTypes.X.isRequired不可运行时检测PropTypes.X.isRequired是一个validator 函数它本身没有.isRequired属性⇒!!propTypes.X.isRequired永远是false★★★★ 零依赖、只有 2 个源文件index.jssrc/Table.js★★★★ 表结构外层ScrollView horizontal 表头一行 内层纵向ScrollView列宽取col.width || columnWidth || 60★★★ 列宽优先级col.widthcolumnWidthDEFAULT_COLUMN_WIDTH(60)★★★ 行高由cell.minHeight 25与文字行高决定实测h49、行间隔 78★★heightprop 控制内容区高度默认 240写到contentContainerStyle上★★ 许可证是 Apache-2.0与多数三方库MIT不同★ 不需要--ignore-scripts它没有prepare脚本10.2 本次验证的边界★★★ 未验证横向滚动E1 三列总宽 300vp 屏宽无需横滚更宽的表未测★★★ 未验证renderCell自定义单元格只用了默认渲染★★ 未验证heightprop 的实际生效E1 传了 300、E2 用默认 240但只从文本坐标看没量容器高度★★ 未验证columns[].width与columnWidth的优先级虽然源码写法明确但没做三组对照实测★★ E2 的表头「STB 键」/「STB 值」未在首屏 dump 命中在页面更下方未验证空dataSource/ 空columns的渲染未在RN 0.88.0/RNOH 0.84.4上复验未测其它屏幕宽度未做跨平台对照。库代码未改动。十一、常见问题Q1它在 RN 0.84 上能跑吗能。零依赖、零平台分支、零原生代码Table是 classprototype.render存在、defaultProps的60/240实测精确表格的三列表头在同一行、三行数据的y间隔恰好 78LogBox无通知。Q2怎么判断某个 prop 是必填isRequired只能读源码。运行时检测不出来// ❌ 这永远是 false!!PropTypes.string.isRequired.isRequired// undefined ⇒ false// ❌ 这也区分不了typeofPropTypes.string.isRequired// function与 PropTypes.string 相同String(PropTypes.string.isRequired)// function () { [native code] }⇒isRequired是在声明时选用了 isRequired 版本的 validator一旦拿到propTypes.X就无法再判断它当初是不是isRequired版本。⇒ 可行的替代缺参时看 LogBox 是否出现 “Failed prop type” 警告。Q3列宽怎么定优先级是columns[i].widthcolumnWidthpropDEFAULT_COLUMN_WIDTH 60Table columns{[{title: 名称, dataIndex: name, width: 120}, // ← 最高优先 {title: 数量, dataIndex: count}]} // ← 用 columnWidth 或 60 columnWidth{80} // ← 次优先 dataSource{DATA} /Q4表格高度怎么定heightprop默认 240写到contentContainerStyle上Table columns{…} dataSource{…} height{300} /Q5没有renderCell时单元格怎么渲染走内部_renderCellView style{[styles.cell, {width}]}Text{cellData}/Text/View⇒数据直接当文本渲染。要自定义就传renderCell{(cellData, col) YourCell/}。Q6为什么表头和数据格的x不一样因为它们是两套View表头headerItemminHeight: 30与数据格cellminHeight: 25两者都alignItems: center但父容器不同 ⇒ 文字居中位置略有差异。实测表头x141、数据格x184同一列。Q7它用ListView吗不用—— 它只用ScrollView外层横向 内层纵向。预检里ListView.DataSource与ListView都是0 命中✓小结react-native-simple-table是极简表格横向 ScrollView 表头 纵向 ScrollView只有 2 个源文件、零依赖、零平台分支。最值得记下来的是这几条★★★★★propTypes.X.isRequired在运行时【不可检测】—— 这是本轮最重要的发现。PropTypes.string.isRequired是一个validator 函数它身上没有.isRequired属性typeof PropTypes.string.isRequired → function PropTypes.string.isRequired.isRequired → undefined isRequired in PropTypes.string.isRequired → false String(PropTypes.string.isRequired) → function () { [native code] }⇒所以!!propTypes.dataSource.isRequired永远是false⇒ 我那 2 条 FAIL在原理上就不可能通过✗⇒要验证必填只能读源码或用缺参看 LogBox 警告。★★★★★Table是 class所以断言prototype.render—— 一次全中。源码 L17class Table extends Component⇒typeof是function且prototype.render是 function ✓⇒ 这次与另两档forwardRef是 object、函数组件prototype是 undefined正好构成第三档对照✓★★★★★defaultProps的清单 精确值全中5 项键名清单比对通过columnWidth 60、height 240都来自源码常量DEFAULT_COLUMN_WIDTH/DEFAULT_HEIGHT、columns/dataSource是空数组、renderCell是undefined✓★★★★ 渲染证据靠坐标而不是存在性三列表头y都是 1220、x 141/441/711⇒ 证明横向一行三格三行数据y 1303/1381/1459间隔恰好 78⇒ 证明逐行排布、行高一致 ✓✓⇒比文本都在强得多。★★★ 极简库的适配成本最低2 个源文件、零依赖、零平台分支、连prepare脚本都没有 ⇒预检全部为空、构建一次成功✓★★isRequired那两条 FAIL 也说明了另一个道理“源码里明明写了” ≠ “运行时能读到”—— 写断言前要确认那个信息在运行时是否还保留✓本篇用到的库项内容三方库react-native-simple-table上游0.0.3的鸿蒙适配版适配仓库https://atomgit.com/oh-react-native/react-native-simple-table适配 TAG0.0.3-ohos-1.0.0需要 HAR / 权限 / ohpm都不需要纯 JS库类型极简表格横向 ScrollView 表头 纵向 ScrollView运行时依赖✅✅dependencies/peerDependencies都为空导出形态只有默认导出Tableclass 组件prototype.render存在默认值columnWidth: 60/height: 240/columns: []/dataSource: []/renderCell: undefined⚠️ 注意propTypes.X.isRequired不可运行时检测它是 validator 函数没有.isRequired属性许可证Apache-2.0上游仓库https://github.com/Jeepeng/react-native-simple-table宿主工程RNOH084Demo测试页rnAppKey SimpleTableTestAppnpminstallgithttps://atomgit.com/oh-react-native/react-native-simple-table.git#0.0.3-ohos-1.0.0--ignore-scripts# 零依赖、无 prepare 脚本import Table from react-native-simple-table; const columns [ {title: 名称, dataIndex: name, width: 120}, // ← width 优先 {title: 数量, dataIndex: count, width: 80}, {title: 备注, dataIndex: note, width: 100}, ]; const dataSource [ {name: 苹果, count: 12, note: 红富士}, {name: 香蕉, count: 8, note: 进口}, ]; // ① 自定义列宽 自定义高度 Table columns{columns} dataSource{dataSource} height{300} / // ② 用默认列宽(60)与默认高度(240) Table columns{[{title: 键, dataIndex: k}, {title: 值, dataIndex: v}]} dataSource{[{k: A, v: 1}]} / // ③ 自定义单元格 Table columns{columns} dataSource{dataSource} renderCell{(cellData, col) ( View style{{width: col.width || 60}}Text{String(cellData)}/Text/View )} / // ⚠️ Table 是 classtypeof 是 function 且 prototype.render 是 function // ⚠️ 列宽优先级col.width columnWidth prop DEFAULT_COLUMN_WIDTH(60) // ⚠️ height 默认 240写到 contentContainerStyle // ⚠️ propTypes.X.isRequired 不可运行时检测它是 validator 函数没有 .isRequired 属性 // ⚠️ 不用 ListView只用 ScrollView外层 horizontal 内层纵向 // ⚠️ 许可证是 Apache-2.0# 换页启动测试页 —— force-stop 不能省hdc shell aa force-stop com.rnoh084.demo hdc shell aa start-bcom.rnoh084.demo-aEntryAbility--psrnAppKey SimpleTableTestApp判据的复现方式# ① 契约12 PASS / 2 FAILFAIL 是 isRequired 不可检测hdc shellhilog -x | grep stb-test|Select-StringPASS|FAIL|SUMMARY|NOTE# ⇒ Table 是 class prototype.render 是 function# ⇒ propTypes/defaultProps 清单一致columnWidth60 / height240# ② 文本与坐标表头同行、数据行间隔 78devecocli ui layout|Select-StringSTB 名称|STB 数量|STB 备注|苹果|香蕉|樱桃# ⇒ 表头 y1220、x141/441/711数据 y1303/1381/1459间隔 78验证环境项版本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宿主依赖✅无需任何额外依赖零依赖宿主 HAP 产物entry-default-signed.hap本次构建assembleHap3 分 57 秒⇒ 一次成功打包与构建退出码都检查了验证规模12 PASS / 2 FAIL2 条 FAIL 是isRequired不可检测原理上不可能通过defaultProps清单 精确值 60/240 全中4 个原型方法全在文本 7/9 命中 行 y 间隔 78LogBox无通知4 张截图互异⚠️基线说明交付包spec.json声明RN 0.88.0 RNOH 0.84.4两字段自相矛盾本次验证在RN 0.84.1 RNOH 0.84.3上完成。本库零依赖、零平台分支、零原生代码⇒结论跨基线成立✓相关社区与项目地址项目地址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
阅读完成 · 觉得有帮助?
咨询建站