feat: RN 环境支持 sectionList 组件#2511
Conversation
|
|
||
| function isReactComponent (el) { | ||
| return !isComponentNode(el) && isRealNode(el) && !el.isBuiltIn | ||
| return !isComponentNode(el) && isRealNode(el) && !el.isBuiltIn && !isExtendComponentNode(el) |
| itemLayouts: layouts, | ||
| getItemLayout: (data: any, index: number) => layouts[index] | ||
| } | ||
| }, [convertedListData, useListHeader, itemHeight.value, itemHeight.getter, sectionHeaderHeight.value, sectionHeaderHeight.getter, sectionFooterHeight.value, sectionFooterHeight.getter, listHeaderHeight.value, listHeaderHeight.getter]) |
There was a problem hiding this comment.
itemHeight.value, itemHeight.getter 为啥需要两种形式来着?
|
|
||
| if (useListHeader) { | ||
| // 计算列表头部的高度 | ||
| offset += listHeaderHeight.getter?.() || listHeaderHeight.value || 0 |
There was a problem hiding this comment.
类似这种不传递参数的getter直接让用户传递固定数值即可
| } | ||
|
|
||
| // 遍历所有 sections | ||
| convertedListData.forEach((section: Section, sectionIndex: number) => { |
| @@ -0,0 +1,60 @@ | |||
| const { EXTEND_COMPONENT_CONFIG } = require('../utils/const') | |||
There was a problem hiding this comment.
可以基于现有的文件条件编译机制实现,不用单独添加resolver
| @@ -0,0 +1 @@ | |||
| <!-- sticky-header placeholder --> | |||
There was a problem hiding this comment.
sticky-header和sticky-section是微信现有的组件,走内建组件注入的形式而不是走extends的形式
- 将 sticky-header、sticky-section 接入模板内建组件转换 - 调整 RN section-list 属性命名与头尾高度配置 - 同步更新扩展组件、RN 组件文档及 mpx2rn skill 参考
- 移除 sticky-header/sticky-section 占位组件 - 更新 RN 组件文档中的 sticky-section/sticky-header 说明 - 调整 section-list 头尾组件数据传递,确保 listHeaderData/listFooterData 更新触发渲染
- 组合 style 移入 scrollAdditionalProps,避免被 innerProps.style 覆盖导致
height/width/layoutStyle 丢失
- 对齐 mpx-scroll-view,未显式设置 flex/flexGrow 时默认追加 flexGrow: 0,
避免 RN ScrollView baseStyle 的 flexGrow: 1 把 height 拉伸成 100%
ExtendComponentsPlugin 到 file 阶段解析 - 将 ExtendComponentsPlugin 从 before-file -> resolve 改为 before-file -> file - 在 file 阶段直接重定向扩展组件的 path/ relativePath - 跳过已处理的扩展组件请求,避免重复解析
| } | ||
| } | ||
|
|
||
| function getComponentName (request) { |
| @@ -0,0 +1,549 @@ | |||
| import { forwardRef, useRef, useState, useEffect, useMemo, createElement, useImperativeHandle, memo } from 'react' | |||
There was a problem hiding this comment.
onRefresh / onEndReached / onScroll 未 useCallback,每次渲染都生成新引用,会被作为 prop 传到 SectionList,触发不必要的子树渲染。参考 mpx-scroll-view.tsx 内对 throttle/scroll 回调的处理。
scrollAdditionalProps.style 用 […] 数组字面量,每次渲染都产生新 ref,可考虑 useMemo。
useState(!!refresherTriggered) + useEffect 同步外部 prop 的写法:与 mpx-scroll-view.tsx:933-941 中现有方案保持一致即可,但可考虑直接受控(去掉 state)以减少状态机分支。
getGeneric 在每次 useMemo 中重新 memo(forwardRef(…)) 包一层:每次 generichash 或 key 变化都会创建新组件类型,挂载的子组件状态会丢失。建议把工厂提到模块顶层并缓存,或直接复用 __mpxGenericsMap 的引用。
hasOwn(style, 'flex') || hasOwn(style, 'flexGrow') ? null : { flexGrow: 0 }:可用 useMemo 缓存。
| // 检查组件是否在配置中 | ||
| const supportedModes = EXTEND_COMPONENTS[componentName] | ||
| if (!supportedModes) { | ||
| return callback(new Error(`Extended component "${componentName}" was not found. Available extended components: ${Object.keys(EXTEND_COMPONENTS).join(', ')}`)) |
There was a problem hiding this comment.
return callback(),用 webpack 的 compilation.errors.push 而不是直接 reject resolve。下同
| if (!position) return | ||
| const [sectionIndex, itemIndex] = position.split('_') | ||
| const targetSectionIndex = Number(sectionIndex) || 0 | ||
| const targetItemIndex = itemIndex === 'header' |
There was a problem hiding this comment.
1.3 scrollToIndex 对 footer 的 itemIndex 偏移可能有误
packages/webpack-plugin/lib/runtime/components/react/mpx-section-list.tsx:618-625
const targetItemIndex = itemIndex === 'header'
? 0
: itemIndex === 'footer'
? convertedListData[targetSectionIndex].data.length + 1
: Number(itemIndex) + 1
RN 的 SectionList.scrollToLocation 中 itemIndex 的含义:
0 = section header
1..data.length = data 项
data.length + 1 才会被识别为 section footer(在某些版本里则是越界)
这里 data.length + 1 实际算到了 data 之后的第一个槽位。如果 section 内 data 长度为 N:
第一项 itemIndex = 1,最后一项 itemIndex = N
footer 在不同 RN 版本中需要传 N + 1(有 header)或 N(无 header 时少一格)
| @@ -0,0 +1 @@ | |||
| <!-- section-list placeholder --> | |||
There was a problem hiding this comment.
1.4 占位 .mpx 文件可能被 loader 误处理
packages/webpack-plugin/lib/runtime/components/extends/section-list.mpx 内容是 。
理论上 resolver 在 before-file 阶段就把请求重定向到 dist/mpx-section-list.jsx,placeholder 永远不会进 loader。但要确保:
如果用户在 @mpx-options.target = 'web' 之类的环境下使用、或在 IDE 中错误地直接 import 这个文件,loader 处理这个空 mpx 会 crash 还是 warn?
推荐改为合法的最小 mpx 内容()或注释里写明用途,避免后续维护困惑:
No description provided.