-
-
Notifications
You must be signed in to change notification settings - Fork 616
fix: table onCell-method cause offset in width calculation #1315
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
fix: table onCell-method cause offset in width calculation #1315
Conversation
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. Walkthrough引入按行粘性偏移支持: Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant BR as BodyRow
participant RI as useRowInfo
participant US as useStickyOffsets
participant GCP as getCellProps
participant GFI as getCellFixedInfo
BR->>RI: 读取 flattenColumns、colWidths、record、index 等
BR->>BR: 遍历列,调用 column.onCell 构建 cellPropsCache,并计算 hasColSpanZero
alt hasColSpanZero
BR->>US: useStickyOffsets(colWidths, flattenColumns, {record,rowIndex})
else
BR->>US: useStickyOffsets(colWidths, flattenColumns)
end
BR->>GCP: getCellProps(..., rowStickyOffsets, hasColSpanZero, cachedCellProps)
note over GCP,GFI: 若列为 fixed 且 hasColSpanZero 且 提供 rowStickyOffsets
GCP->>GFI: getCellFixedInfo(colIndex, colIndex, flattenColumns, rowStickyOffsets)
GFI-->>GCP: 返回固定列位置信息
GCP-->>BR: 返回带 fixed/offset 的 cell props
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60–75 minutes Possibly related PRs
Suggested reviewers
Poem
Tip 🔌 Remote MCP (Model Context Protocol) integration is now available!Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats. 📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 💡 Knowledge Base configuration:
You can enable these sources in your CodeRabbit configuration. 📒 Files selected for processing (4)
🚧 Files skipped from review as they are similar to previous changes (4)
✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Summary of Changes
Hello @cactuser-Lu, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!
此PR旨在修复表格组件中,当固定列与onCell
方法结合使用进行单元格合并时,由于colSpan
返回0导致宽度计算偏移不正确的问题。这会导致固定列出现重叠或错位。通过在BodyRow
组件中动态调整useStickyOffsets
的计算逻辑,确保colSpan
为0的列的宽度被正确排除,从而修正了固定列的偏移量。
Highlights
- 表格行处理: 在
BodyRow
组件中引入新的逻辑,以检测行中是否存在colSpan
为0的单元格,并根据此信息动态调整固定列的偏移量计算。 - 粘性偏移量计算: 修改
useStickyOffsets
钩子,使其能够根据单元格的onCell
属性动态获取colSpan
值,并在计算固定列偏移时排除colSpan
为0的列的宽度。 - 单元格属性处理: 更新了单元格属性获取函数
getCellProps
,使其在计算固定列的fixedInfo
时,能够利用新的行级粘性偏移量信息。 - 行信息钩子: 调整了
useRowInfo
钩子,以传递列宽信息,支持BodyRow
中更精确的宽度计算。
Using Gemini Code Assist
The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.
Invoking Gemini
You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command>
or @gemini-code-assist <command>
. Below is a summary of the supported commands.
Feature | Command | Description |
---|---|---|
Code Review | /gemini review |
Performs a code review for the current pull request in its current state. |
Pull Request Summary | /gemini summary |
Provides a summary of the current pull request in its current state. |
Comment | @gemini-code-assist | Responds in comments when explicitly tagged, both in issue comments and review comments. |
Help | /gemini help |
Displays a list of available commands. |
Customization
To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/
folder in the base of the repository. Detailed instructions can be found here.
Limitations & Feedback
Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.
You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.
Footnotes
-
Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
您好,感谢您对修复表格 onCell
方法导致固定列宽度计算偏移问题的贡献。整体的修复思路是正确的,通过在行级别动态计算 sticky
偏移量来解决 colSpan=0
带来的布局问题。我发现有两处可以改进的地方:一处是 useStickyOffsets
钩子中的逻辑可能引入新问题,另一处是 BodyRow
中存在性能优化的空间。请查看我的具体建议。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (6)
src/hooks/useRowInfo.tsx (1)
109-124
: 避免返回整个 context,减小不必要的重渲染面当前直接
...context
会把 TableContext 的全部字段都放进返回对象,这会让依赖useRowInfo
的组件在 context 其它无关字段变化时也产生重渲染。建议仅返回 Pick 中声明的键,保持“最小暴露面”。不影响功能,但可作为一次小的性能与可维护性优化。可以考虑如下精简(仅示意主要键,按需补全),保持类型与实际使用一致:
- return { - ...context, + return { + prefixCls: context.prefixCls, + fixedInfoList: context.fixedInfoList, + flattenColumns: context.flattenColumns, + colWidths: context.colWidths, + expandableType: context.expandableType, + expandRowByClick: context.expandRowByClick, + onTriggerExpand: onInternalTriggerExpand, + rowClassName: context.rowClassName, + expandedRowClassName: context.expandedRowClassName, + indentSize: context.indentSize, + expandIcon: context.expandIcon, + expandedRowRender: context.expandedRowRender, + expandIconColumnIndex: context.expandIconColumnIndex, + expandedKeys: context.expandedKeys, + childrenColumnName: context.childrenColumnName, + onRow: context.onRow, columnsKey, nestExpandable, expanded, hasNestChildren, record, - onTriggerExpand: onInternalTriggerExpand, rowSupportExpand, expandable: mergedExpandable, rowProps: { ...rowProps, className: classNames(computeRowClassName, rowProps?.className), onClick, }, };src/hooks/useStickyOffsets.ts (1)
23-37
: 仅在“对应侧”累加宽度,避免无意义的宽度累加;同时不要在无 rowContext 时读取列级 colSpan
- 目前
total += ...
的判定是column.fixed && colSpan !== 0
,这会在计算 start(左固定)时也把“右固定列”的宽度累加进start
的中间态值;虽然最终不会被取用(右固定位使用end
),但会平白增加计算噪音,且不利于日后维护。- 当
rowContext
不存在时,使用column.colSpan ?? 1
作为回退可能会误将“列定义层面的 colSpan(更偏向表头语义)”带入“行内单元格”逻辑,改变既有行为。建议在无rowContext
时统一按1
处理。建议如下精确到“固定方向”的实现,同时移除列级 colSpan 回退(保持无 rowContext 时的行为与历史一致):
- const getOffsets = (startIndex: number, endIndex: number, offset: number) => { + const getOffsets = ( + startIndex: number, + endIndex: number, + offset: number, + side: 'start' | 'end', + ) => { const offsets: number[] = []; let total = 0; for (let i = startIndex; i !== endIndex; i += offset) { const column = flattenColumns[i]; offsets.push(total); - let colSpan = 1; - if (rowContext) { - const cellProps = column.onCell?.(rowContext.record, rowContext.rowIndex) || {}; - colSpan = cellProps.colSpan ?? 1; - } else { - colSpan = column.colSpan ?? 1; - } + // 仅逐行模式下解析 colSpan;否则默认 1 + const colSpan = + rowContext + ? (column.onCell?.(rowContext.record, rowContext.rowIndex)?.colSpan ?? 1) + : 1; - if (column.fixed && colSpan !== 0) { + const isFixedStart = column.fixed === true || column.fixed === 'left'; + const isFixedEnd = column.fixed === 'right'; + const shouldCount = side === 'start' ? isFixedStart : isFixedEnd; + if (shouldCount && colSpan !== 0) { total += colWidths[i] || 0; } } return offsets; }; - const startOffsets = getOffsets(0, columnCount, 1); - const endOffsets = getOffsets(columnCount - 1, -1, -1).reverse(); + const startOffsets = getOffsets(0, columnCount, 1, 'start'); + const endOffsets = getOffsets(columnCount - 1, -1, -1, 'end').reverse();这样可以:
- 排除与当前侧无关的固定列宽度,降低心智负担;
- 避免将“列定义层面的 colSpan”误用于 Body 的单元格宽度折算。
请用右固定列(例如最后两列 fixed: 'right')的场景跑一下回归,确认
end
偏移与历史版本一致;同时验证本 PR 提到的 0/1 列左固定 + colSpan=0/2 的复现用例在该实现下仍然正确。src/Body/BodyRow.tsx (4)
70-72
: 当前条件将所有 fixed 单元都走“逐行偏移”路径;建议仅在需要时启用这里判断为
column.fixed && rowStickyOffsets
,而上层始终会调用useStickyOffsets(...)
,因此rowStickyOffsets
永远为真。这样在“没有 colSpan=0”的常规场景中也会放弃使用既有的fixedInfoList[colIndex]
。为尽量减少无关行为差异,建议仅在本行确实存在colSpan=0
时才传入rowStickyOffsets
,否则传undefined
让代码走旧路径。对应改动建议在调用处(见下条评论)按需传参。
162-168
: hasColSpanZero 会对全列调用一次 onCell,后续每个单元格还会再调一次 onCell(在 getCellProps 中),存在重复计算在逐行开启 sticky 的场景下,
onCell
可能被调用两次(检测 + 取 additional props)。可以考虑做一个轻量缓存(例如 Map<colIndex, cellProps>)在本行生命周期内复用,以减少自定义 onCell 的开销。这是性能微优化,不影响本次修复的正确性。示意实现(不要求本 PR 内必改):
+ const cellPropsCache = React.useMemo(() => { + const m = new Map<number, any>(); + flattenColumns.forEach((col, i) => { + const props = col.onCell?.(record, index) || {}; + m.set(i, props); + }); + return m; + }, [flattenColumns, record, index]); + - const hasColSpanZero = React.useMemo(() => { - return flattenColumns.some(col => { - const cellProps = col.onCell?.(record, index) || {}; - return (cellProps.colSpan ?? 1) === 0; - }); - }, [flattenColumns, record, index]); + const hasColSpanZero = React.useMemo( + () => Array.from(cellPropsCache.values()).some(p => (p.colSpan ?? 1) === 0), + [cellPropsCache], + );随后在 getCellProps 调用处优先读取
cellPropsCache.get(colIndex)
并作为 fallback 传入,避免重复求值。
169-174
: useStickyOffsets 无条件执行没问题,但可减少对新逻辑的“误用”Hook 必须在同一顺序调用,当前写法是正确的。但结合上一条建议,你可以只在
hasColSpanZero
为真时将返回值传递下去(否则传undefined
),以避免正常行也走逐行路径带来潜在行为差异。
263-266
: 关于阴影与可视宽度:逐行 sticky 下的阴影偏移可能仍受 widths(未排除 colSpan=0)影响
getCellFixedInfo
中计算阴影偏移(offsetFixedStartShadow/offsetFixedEndShadow
)依赖stickyOffsets.widths
。当前我们仅在start/end
偏移处排除了colSpan=0
的列宽,widths
仍是原始colWidths
。在左/右固定列前存在被合并(colSpan=0)但非固定的列时,阴影长度可能略有偏差。建议在真实用例下观察,如有视觉差异,可考虑在fixUtil
中对阴影偏移的计算也引入逐行 colSpan 的判定(可后续 PR 跟进)。
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (3)
src/Body/BodyRow.tsx
(6 hunks)src/hooks/useRowInfo.tsx
(2 hunks)src/hooks/useStickyOffsets.ts
(3 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: bbb169
PR: react-component/table#1202
File: src/Table.tsx:903-904
Timestamp: 2024-11-08T12:53:09.293Z
Learning: 在 `src/Table.tsx` 文件的 React 组件 `Table` 中,即使 `bodyScrollLeft` 频繁更新,也需要在 `TableContextValue` 的 `useMemo` 依赖数组中包含 `bodyScrollLeft` 和 `headerCellRefs`,因为每次滚动时重新计算 `TableContextValue` 是解决该问题所必须的。
📚 Learning: 2024-11-08T12:53:09.293Z
Learnt from: bbb169
PR: react-component/table#1202
File: src/Table.tsx:903-904
Timestamp: 2024-11-08T12:53:09.293Z
Learning: 在 `src/Table.tsx` 文件的 React 组件 `Table` 中,即使 `bodyScrollLeft` 频繁更新,也需要在 `TableContextValue` 的 `useMemo` 依赖数组中包含 `bodyScrollLeft` 和 `headerCellRefs`,因为每次滚动时重新计算 `TableContextValue` 是解决该问题所必须的。
Applied to files:
src/Body/BodyRow.tsx
🧬 Code graph analysis (2)
src/hooks/useStickyOffsets.ts (1)
src/interface.ts (1)
ColumnType
(118-133)
src/Body/BodyRow.tsx (1)
src/utils/fixUtil.ts (1)
getCellFixedInfo
(33-102)
🔇 Additional comments (5)
src/hooks/useRowInfo.tsx (1)
18-19
: 补充透出 colWidths 的方向正确,契合本 PR 的修复思路useRowInfo 现在将
colWidths
从 TableContext 取出并作为返回值透出,配合 BodyRow 的逐行 sticky 计算是必须的。依赖键也同步加入了colWidths
,一致性良好。无功能性风险点。Also applies to: 45-46
src/hooks/useStickyOffsets.ts (2)
6-9
: JSDoc 较为清晰,参数扩展说明到位新增
rowContext
参数的目的描述清晰,有助于理解“逐行”场景下的 colSpan 参与计算的时机。
50-53
: 依赖项选择基本合理,但仍建议关注 record 引用稳定性
useMemo
依赖包含了rowContext.record
与rowIndex
,可以正确触发逐行重算。请确认上层传入的record
引用在数据未变更时尽量保持稳定,以减少不必要的重算。若无法保证,可考虑在上层进行浅比较或稳定化处理。src/Body/BodyRow.tsx (2)
48-49
: getCellProps 新增 rowStickyOffsets 入参的接口扩展是必要的为逐行 colSpan=0 的场景重新计算 fixedInfo 提供了入口,接口设计符合最小改动原则。
211-220
: 仅在检测到本行存在 colSpan=0 时传入 rowStickyOffsets,以保持非粘滞场景的旧行为这样能最大限度降低回归风险,且与修复目标更吻合。
[ suggest_optional_refactor ]
const { key, fixedInfo, appendCellNode, additionalCellProps } = getCellProps( rowInfo, column, colIndex, indent, index, rowKeys, expandedRowInfo?.offset, - rowStickyOffsets, + hasColSpanZero ? rowStickyOffsets : undefined, );
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (1)
src/Body/BodyRow.tsx (1)
220-222
: 仅在存在 colSpan=0 时传入 rowStickyOffsets 并重算 fixedInfo,已落实之前建议此变更响应了先前建议“仅在必要时重算 fixedInfo”,避免对每一固定列在每一行都进行重复计算,性能更可控。
🧹 Nitpick comments (4)
src/Body/BodyRow.tsx (4)
153-154
: 首次渲染/测量阶段 colWidths 可能为空的防御性考量当列宽尚未测量完成时,
colWidths
可能长度为 0 或与flattenColumns.length
不一致。虽然useStickyOffsets
往往内部会兜底,但为避免边界闪动或不必要的重算,建议在开发环境下做一次长度一致性告警,便于排查异常来源(列增删或合并导致的错配)。可以考虑在开发模式加入轻量校验(示意,非必须):
if (process.env.NODE_ENV !== 'production' && colWidths && colWidths.length !== flattenColumns.length) { // eslint-disable-next-line no-console console.warn('[BodyRow] colWidths length mismatch with flattenColumns:', colWidths.length, flattenColumns.length); }
163-169
: 避免对同一行重复调用多次 onCell:可缓存以降低开销并规避潜在副作用这里用
some(col => col.onCell?.(record, index))
来探测colSpan===0
,稍后在getCellProps
内又会再次调用column.onCell(record, index)
生成additionalCellProps
。在大表或虚拟滚动场景下,双次调用既有性能成本,也放大了 onCell 的潜在副作用(虽然我们期望它是纯函数)。建议缓存一次 onCell 结果并在两处复用:
可以在此处引入缓存(示例 diff,仅涉及当前代码块;配套在调用点处需要读取该缓存,见下方“额外改动”):
- const hasColSpanZero = React.useMemo(() => { - return flattenColumns.some(col => { - const cellProps = col.onCell?.(record, index) || {}; - return (cellProps.colSpan ?? 1) === 0; - }); - }, [flattenColumns, record, index]); + const onCellPropsByColIndex = React.useMemo( + () => flattenColumns.map(col => col.onCell?.(record, index) || {}), + [flattenColumns, record, index], + ); + const hasColSpanZero = React.useMemo( + () => onCellPropsByColIndex.some(p => (p.colSpan ?? 1) === 0), + [onCellPropsByColIndex], + );额外改动(在本块之外):在调用
getCellProps
时,可将预计算的onCellPropsByColIndex[colIndex]
作为入参传入,避免二次调用onCell
。如有需要,我可以补充完整的最小改动方案。
212-219
: (可选)调用参数序列可读性改进
getCellProps
参数较长,末尾两个与“逐行 colSpan 修正”强相关。为了降低误传/错序风险,可将它们合并为一个 options 对象传入(例如{ expandedRowOffset, rowStickyOffsets, hasColSpanZero }
),从而提升可读性与可维护性。此为可选建议。
114-120
: 建议补充用例覆盖“首两列固定 + 第0列 colSpan=0 + 第1列 colSpan=2”的回归测试为防止未来回归,建议在 e2e 或可视化单测中补充用例,断言:
- 第1列固定单元格的
left
偏移为 0(而非width[0]
)- 第1列单元格宽度为
width[0]+width[1]
- 滚动与展开/收起状态切换后偏移保持正确
如需要,我可以基于现有测试框架补充最小可复现用例。
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (2)
src/Body/BodyRow.tsx
(6 hunks)src/hooks/useStickyOffsets.ts
(3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- src/hooks/useStickyOffsets.ts
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: bbb169
PR: react-component/table#1202
File: src/Table.tsx:903-904
Timestamp: 2024-11-08T12:53:09.293Z
Learning: 在 `src/Table.tsx` 文件的 React 组件 `Table` 中,即使 `bodyScrollLeft` 频繁更新,也需要在 `TableContextValue` 的 `useMemo` 依赖数组中包含 `bodyScrollLeft` 和 `headerCellRefs`,因为每次滚动时重新计算 `TableContextValue` 是解决该问题所必须的。
📚 Learning: 2024-11-08T12:53:09.293Z
Learnt from: bbb169
PR: react-component/table#1202
File: src/Table.tsx:903-904
Timestamp: 2024-11-08T12:53:09.293Z
Learning: 在 `src/Table.tsx` 文件的 React 组件 `Table` 中,即使 `bodyScrollLeft` 频繁更新,也需要在 `TableContextValue` 的 `useMemo` 依赖数组中包含 `bodyScrollLeft` 和 `headerCellRefs`,因为每次滚动时重新计算 `TableContextValue` 是解决该问题所必须的。
Applied to files:
src/Body/BodyRow.tsx
🧬 Code graph analysis (1)
src/Body/BodyRow.tsx (1)
src/utils/fixUtil.ts (1)
getCellFixedInfo
(33-102)
🔇 Additional comments (4)
src/Body/BodyRow.tsx (4)
11-12
: 引入逐行 sticky 偏移计算相关依赖 ✅新增
useStickyOffsets
与getCellFixedInfo
的 import 与本次修复方向一致,能支撑“按行动态修正偏移”的方案。无循环依赖迹象。
56-57
: 解构引入 flattenColumns 用于重算 fixedInfo,方向正确
flattenColumns
在getCellProps
中用于getCellFixedInfo
的重算,能与“逐行 stickyOffsets”配合;命名与上下文一致。
170-175
: 逐行 sticky 偏移计算触发条件与参数选择合理仅当
hasColSpanZero
为真时才传入rowContext
,避免了对全量行的额外计算压力;以colWidths + flattenColumns + rowContext
为依赖可确保在列宽变更或合并规则变化时正确更新。
48-50
: 无需更新:getCellProps
新增的可选参数不会引入 Breaking Change
经全量检索,仓库中仅存在以下调用点:
- src/Body/BodyRow.tsx 内部对自身声明的调用
- src/VirtualTable/VirtualCell.tsx 两处调用(仅传递前三个必需参数)
新增的
rowStickyOffsets?
和hasColSpanZero?
都是可选且位于参数尾部,现有调用无需传参即可正常工作,故不影响兼容性。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/Body/BodyRow.tsx (1)
94-112
: 严重:不要原地修改缓存的 onCell 结果对象,rowSpan 会在重渲染中累加并污染 useMemo 缓存当前
additionalCellProps
直接引用了cellPropsCache[colIndex]
。后续对additionalCellProps.rowSpan
的赋值会“脏写”缓存对象,导致:
- 下一次渲染读取到已经被修改过的
rowSpan
,从而再次累加,出现行高异常;cellPropsCache
的 useMemo 在依赖不变时仍持有被污染的对象,产生隐性状态泄漏。建议对
cachedCellProps
进行浅拷贝后再修改,且以未拷贝的基值作为计算基线:- const additionalCellProps = cachedCellProps || column.onCell?.(record, index) || {}; + const baseCellProps = cachedCellProps ?? column.onCell?.(record, index) ?? {}; + const additionalCellProps = { ...baseCellProps }; // Expandable row has offset if (expandedRowOffset) { - const { rowSpan = 1 } = additionalCellProps; + const baseRowSpan = baseCellProps.rowSpan ?? 1; // For expandable row with rowSpan, // We should increase the rowSpan if the row is expanded - if (expandable && rowSpan && colIndex < expandedRowOffset) { - let currentRowSpan = rowSpan; + if (expandable && baseRowSpan && colIndex < expandedRowOffset) { + let currentRowSpan = baseRowSpan; - for (let i = index; i < index + rowSpan; i += 1) { + for (let i = index; i < index + baseRowSpan; i += 1) { const rowKey = rowKeys[i]; if (expandedKeys.has(rowKey)) { currentRowSpan += 1; } } additionalCellProps.rowSpan = currentRowSpan; } }
♻️ Duplicate comments (1)
src/Body/BodyRow.tsx (1)
70-74
: 修复点确认:仅在存在 colSpan=0 的行上按需重算 fixedInfo,正确排除被隐藏列宽度
- 判断条件
column.fixed && hasColSpanZero && rowStickyOffsets
精准,避免无谓重算并修复偏移错误。- 这也响应了先前评审中“仅在 hasColSpanZero 时重算”的建议。做得好。
🧹 Nitpick comments (5)
src/Body/BodyRow.tsx (5)
11-12
: 类型解耦建议:导出函数签名不应依赖 hook 的 ReturnType
getCellProps
形参类型写成ReturnType<typeof useStickyOffsets>
会把实现细节(hook)泄露到公共 API,并造成 d.ts 可读性与稳定性下降。建议使用框架内已有的结构化类型StickyOffsets
(fixUtil.ts 已在使用),仅做类型导入:
- 优点:API 稳定、避免循环依赖、文档友好。
示例(按你们的类型定义落点调整 import 路径即可):
+ import type { StickyOffsets } from '../interface'; export function getCellProps<RecordType>( ... - rowStickyOffsets?: ReturnType<typeof useStickyOffsets>, + rowStickyOffsets?: StickyOffsets, ... ) { ... }Also applies to: 48-49
50-51
: 把 cachedCellProps 精确标注为 onCell 的返回类型,去除 any当前
cachedCellProps?: Record<string, any>
过于宽泛。可直接从列定义上推导返回类型,既减少 any 扩散,也便于 IDE 补全与约束。- cachedCellProps?: Record<string, any>, + cachedCellProps?: ReturnType<NonNullable<ColumnType<RecordType>['onCell']>>,配合上一个评论中的“浅拷贝”修正,可完全避免对未知结构的原地写入。
Also applies to: 94-95
168-176
: 减少不必要的粘性偏移重算:对 rowContext 做引用稳定化当
hasColSpanZero
为 true 时,每次渲染都会创建新的{ record, rowIndex }
对象,可能导致useStickyOffsets
下游依赖频繁失效。可以用 useMemo 稳定其引用。- const rowStickyOffsets = useStickyOffsets( - colWidths, - flattenColumns, - hasColSpanZero ? { record, rowIndex: index } : undefined, - ); + const rowContext = React.useMemo( + () => (hasColSpanZero ? { record, rowIndex: index } : undefined), + [hasColSpanZero, record, index], + ); + const rowStickyOffsets = useStickyOffsets(colWidths, flattenColumns, rowContext);
268-269
: 可选:ExpandedRow 的 colSpan 在存在 colSpan=0 时可改为“可见列数”以避免空白错位当前退化到
flattenColumns.length
。当本行有若干列colSpan=0
被隐藏时,展开行可能占用过多列数产生多余空白。可以用cellPropsCache
计算可见列数量:+ // 统计本行可见列数(排除 colSpan=0) + const visibleColCount = React.useMemo( + () => cellPropsCache.filter(cp => ((cp.colSpan ?? 1) !== 0)).length, + [cellPropsCache], + ); ... - colSpan={expandedRowInfo ? expandedRowInfo.colSpan : flattenColumns.length} + colSpan={expandedRowInfo ? expandedRowInfo.colSpan : visibleColCount}此改动会改变展开行在合并列场景下的占位逻辑,请在 demo 中确认视觉符合预期。
126-283
: 补充回归测试:覆盖“固定列 + colSpan=0/2 合并”的宽度与偏移建议新增用例,确保本修复不被后续改动回归:
- 左侧固定第 0、1 列;
- 第 0 列 onCell:在 index === 1 时返回 { colSpan: 0 };
- 第 1 列 onCell:在 index === 1 时返回 { colSpan: 2 };
- 断言:第 1 列在该行的
left
偏移不包含第 0 列宽度(应为 0),且合并单元格宽度为 width[0] + width[1];- 覆盖展开行存在/不存在两种情况。
如需,我可以基于现有测试框架起草测试代码。
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
src/Body/BodyRow.tsx
(7 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: bbb169
PR: react-component/table#1202
File: src/Table.tsx:903-904
Timestamp: 2024-11-08T12:53:09.293Z
Learning: 在 `src/Table.tsx` 文件的 React 组件 `Table` 中,即使 `bodyScrollLeft` 频繁更新,也需要在 `TableContextValue` 的 `useMemo` 依赖数组中包含 `bodyScrollLeft` 和 `headerCellRefs`,因为每次滚动时重新计算 `TableContextValue` 是解决该问题所必须的。
📚 Learning: 2024-11-08T12:53:09.293Z
Learnt from: bbb169
PR: react-component/table#1202
File: src/Table.tsx:903-904
Timestamp: 2024-11-08T12:53:09.293Z
Learning: 在 `src/Table.tsx` 文件的 React 组件 `Table` 中,即使 `bodyScrollLeft` 频繁更新,也需要在 `TableContextValue` 的 `useMemo` 依赖数组中包含 `bodyScrollLeft` 和 `headerCellRefs`,因为每次滚动时重新计算 `TableContextValue` 是解决该问题所必须的。
Applied to files:
src/Body/BodyRow.tsx
🧬 Code graph analysis (1)
src/Body/BodyRow.tsx (1)
src/utils/fixUtil.ts (1)
getCellFixedInfo
(33-102)
🔇 Additional comments (2)
src/Body/BodyRow.tsx (2)
40-51
: 确认无需关注向后兼容性变更:getCellProps 仅作内部使用,可安全添加可选参数
- 仓库内仅有两处调用
src/VirtualTable/VirtualCell.tsx
(第 58–62 行)src/Body/BodyRow.tsx
(第 212–216 行)- 类型声明文件中无任何
.d.ts
暴露getCellProps
新增的三个参数均为末尾可选参数,不会影响现有调用,符合 JavaScript/TypeScript 的向后兼容性原则,无需进一步操作。
164-167
: 确认 Cell 组件内部无 onCell 调用,可放心使用预计算经脚本验证,
src/Footer/Cell.tsx
中未检测到任何onCell(
或onCell
引用,说明<Cell>
内部不会再次调用column.onCell
,cellPropsCache
能有效避免重复执行复杂逻辑,无需额外修改。
- 验证位置:
src/Footer/Cell.tsx
- 验证结果:未发现
onCell
调用或引用
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR fixes an issue with sticky column offset calculation when using onCell
method for table column merging. When columns have colSpan: 0
, they are visually hidden but their widths were still being included in sticky offset calculations, causing misalignment and overlap of fixed columns.
- Adds row context support to
useStickyOffsets
hook for dynamic colSpan calculation - Implements per-row sticky offset calculation in BodyRow component
- Caches cell properties to avoid redundant
onCell
calls
Reviewed Changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
File | Description |
---|---|
src/hooks/useStickyOffsets.ts | Enhanced to accept row context and exclude colSpan=0 columns from offset calculations |
src/hooks/useRowInfo.tsx | Added colWidths to the exported row information |
src/Body/BodyRow.tsx | Implemented row-level sticky offset calculation with colSpan awareness |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
const cellPropsCache = React.useMemo(() => { | ||
return flattenColumns.map(col => col.onCell?.(record, index) || {}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The cellPropsCache is recalculated on every render when record or index changes. For large tables with many columns, this could be expensive. Consider memoizing individual cell props or using a more granular dependency array.
const cellPropsCache = React.useMemo(() => { | |
return flattenColumns.map(col => col.onCell?.(record, index) || {}); | |
return flattenColumns.map((col, colIdx) => | |
React.useMemo( | |
() => col.onCell?.(record, index) || {}, | |
[col, col.onCell, record, index] | |
) | |
); |
Copilot uses AI. Check for mistakes.
const rowStickyOffsets = useStickyOffsets( | ||
colWidths, | ||
flattenColumns, | ||
hasColSpanZero ? { record, rowIndex: index } : undefined, | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The rowStickyOffsets hook is called on every render even when hasColSpanZero is false. Consider conditionally calling this hook only when needed to avoid unnecessary calculations.
const rowStickyOffsets = useStickyOffsets( | |
colWidths, | |
flattenColumns, | |
hasColSpanZero ? { record, rowIndex: index } : undefined, | |
); | |
const rowStickyOffsets = hasColSpanZero | |
? useStickyOffsets( | |
colWidths, | |
flattenColumns, | |
{ record, rowIndex: index }, | |
) | |
: undefined; |
Copilot uses AI. Check for mistakes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
条件性调用 Hook违反规则
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (3)
tests/FixedColumn.spec.tsx (1)
427-472
: 补强断言:展开行场景下继续验证合并单元格与子行结构建议在“可展开行”用例中补充对父行合并单元格的断言,以及子行不受影响的基础断言,使回归测试覆盖更完整。
const parentRow = allRows[1]; const parentCells = parentRow.querySelectorAll('.rc-table-cell'); expect(parentCells).toHaveLength(2); + // 父行第一个单元格应保持合并 + expect(parentCells[0]).toHaveAttribute('colSpan', '2'); const childRow = allRows[2]; const childCells = childRow.querySelectorAll('.rc-table-cell'); expect(childCells).toHaveLength(3); + // 子行不应受父行合并影响 + expect(childCells[0]).not.toHaveAttribute('colSpan', '0');src/Body/BodyRow.tsx (2)
48-51
: 为 cachedCellProps 提供更精确的类型,减少 any 滥用
cachedCellProps?: Record<string, any>
过于宽泛。考虑收紧到表格单元格可接受的 HTML 属性并显式包含行/列合并字段,有助于类型提示和重构安全。- cachedCellProps?: Record<string, any>, + cachedCellProps?: React.TdHTMLAttributes<HTMLTableCellElement> & { + colSpan?: number; + rowSpan?: number; + },
70-75
: 仅在需要时重算 fixedInfo 的策略正确;进一步兼容 colSpan>1 的固定阴影/层级计算当前在存在
colSpan=0
且提供了rowStickyOffsets
时重算 fixedInfo,能避免把隐藏列宽度计入偏移,方向正确。不过当当前单元格自身存在colSpan>1
时,getCellFixedInfo
的colEnd
仍然使用colIndex
,可能导致阴影/层级计算(如 zIndex 与 shadow 判定)与实际跨列范围不完全一致。建议利用已传入的cachedCellProps
推导colEnd
:- if (column.fixed && hasColSpanZero && rowStickyOffsets) { - fixedInfo = getCellFixedInfo(colIndex, colIndex, flattenColumns, rowStickyOffsets); - } + if (column.fixed && hasColSpanZero && rowStickyOffsets) { + const span = Math.max(1, Number(cachedCellProps?.colSpan ?? 1)); + const colEnd = Math.min(flattenColumns.length - 1, colIndex + span - 1); + fixedInfo = getCellFixedInfo(colIndex, colEnd, flattenColumns, rowStickyOffsets); + }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (1)
tests/__snapshots__/FixedColumn.spec.tsx.snap
is excluded by!**/*.snap
📒 Files selected for processing (2)
src/Body/BodyRow.tsx
(7 hunks)tests/FixedColumn.spec.tsx
(1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: bbb169
PR: react-component/table#1202
File: src/Table.tsx:903-904
Timestamp: 2024-11-08T12:53:09.293Z
Learning: 在 `src/Table.tsx` 文件的 React 组件 `Table` 中,即使 `bodyScrollLeft` 频繁更新,也需要在 `TableContextValue` 的 `useMemo` 依赖数组中包含 `bodyScrollLeft` 和 `headerCellRefs`,因为每次滚动时重新计算 `TableContextValue` 是解决该问题所必须的。
📚 Learning: 2024-11-08T12:53:09.293Z
Learnt from: bbb169
PR: react-component/table#1202
File: src/Table.tsx:903-904
Timestamp: 2024-11-08T12:53:09.293Z
Learning: 在 `src/Table.tsx` 文件的 React 组件 `Table` 中,即使 `bodyScrollLeft` 频繁更新,也需要在 `TableContextValue` 的 `useMemo` 依赖数组中包含 `bodyScrollLeft` 和 `headerCellRefs`,因为每次滚动时重新计算 `TableContextValue` 是解决该问题所必须的。
Applied to files:
src/Body/BodyRow.tsx
🧬 Code graph analysis (2)
tests/FixedColumn.spec.tsx (1)
src/interface.ts (1)
ColumnsType
(135-138)
src/Body/BodyRow.tsx (1)
src/utils/fixUtil.ts (1)
getCellFixedInfo
(33-102)
🔇 Additional comments (4)
tests/FixedColumn.spec.tsx (1)
348-381
: 新增的测试列定义覆盖了关键场景,设计合理
- 固定左侧的第 0/1 列分别返回 colSpan=0 与 colSpan=2(仅第 1 行),能稳定复现并验证粘性偏移的计算修复点。
- 列宽分别为 100/120/150,便于在断言中确认 left/阴影计算是否正确。
src/Body/BodyRow.tsx (3)
164-171
: 按行预取 onCell 与 hasColSpanZero 的判定方式合理提前计算
cellPropsCache
并据此判断是否存在colSpan=0
,从而在需要时开启“按行” sticky 偏移,达到了最小化重算的目的。同时避免在渲染 Cell 时重复调用onCell
。LGTM。
172-177
: 正确使用 Hook:始终调用 useStickyOffsets,仅在需要时传入 rowContext未采用条件调用 Hook 的做法,符合 Hooks 规则;通过传入/省略
rowContext
控制行为,既保证类型与时序安全,也避免无效重算。赞。
214-225
: 参数穿透清晰且向后兼容将
rowStickyOffsets
、hasColSpanZero
与缓存的cellProps
透传给getCellProps
,旧签名保持兼容(新增均为可选参数)。这与修复目标强相关,风险可控。
const hasFixedLeftClass = mergedCell.classList.contains('rc-table-cell-fix-left'); | ||
|
||
if (hasFixedLeftClass) { | ||
const cellStyle = window.getComputedStyle(mergedCell); | ||
expect(cellStyle.left).toBe('0px'); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
让断言更强:固定列类名应为必然条件,且使用逻辑方向属性以避免环境差异
当前以“如果包含 rc-table-cell-fix-left 再断言 left”为条件,可能在类名缺失时静默通过,掩盖回归。并且使用 left
在开启逻辑方向属性(inset-inline-start)的实现或 RTL 下可能不稳定。建议:
- 显式断言单元格具有固定左类名;
- 使用 computedStyle 同时兼容
left
与inset-inline-start
。
[建议变更如下]
- const hasFixedLeftClass = mergedCell.classList.contains('rc-table-cell-fix-left');
-
- if (hasFixedLeftClass) {
- const cellStyle = window.getComputedStyle(mergedCell);
- expect(cellStyle.left).toBe('0px');
- }
+ // 固定左列应当存在
+ expect(mergedCell).toHaveClass('rc-table-cell-fix-left');
+ // 兼容传统属性与逻辑方向属性
+ const cellStyle = window.getComputedStyle(mergedCell);
+ const left = cellStyle.left;
+ const insetInlineStart = cellStyle.getPropertyValue('inset-inline-start');
+ expect(left === '0px' || insetInlineStart === '0px').toBeTruthy();
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const hasFixedLeftClass = mergedCell.classList.contains('rc-table-cell-fix-left'); | |
if (hasFixedLeftClass) { | |
const cellStyle = window.getComputedStyle(mergedCell); | |
expect(cellStyle.left).toBe('0px'); | |
} | |
// 固定左列应当存在 | |
expect(mergedCell).toHaveClass('rc-table-cell-fix-left'); | |
// 兼容传统属性与逻辑方向属性 | |
const cellStyle = window.getComputedStyle(mergedCell); | |
const left = cellStyle.left; | |
const insetInlineStart = cellStyle.getPropertyValue('inset-inline-start'); | |
expect(left === '0px' || insetInlineStart === '0px').toBeTruthy(); |
🤖 Prompt for AI Agents
In tests/FixedColumn.spec.tsx around lines 419 to 424, the test currently
conditionally asserts the computed left when the cell has the
'rc-table-cell-fix-left' class which can silently pass if the class is missing
and uses the physical 'left' property which is unstable in RTL or when logical
inset-inline-start is used; change this to explicitly assert that
mergedCell.classList contains 'rc-table-cell-fix-left' (fail the test if
missing), then read computedStyle and assert that either computedStyle.left ===
'0px' or computedStyle.getPropertyValue('inset-inline-start') === '0px' (i.e.,
require at least one to be '0px') so the test is both strict about the class
presence and robust across logical/physical CSS directions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (1)
src/hooks/useStickyOffsets.ts (1)
27-31
: 移除了回退到 column.colSpan 的逻辑,修正了过去的误用当 rowContext 不存在时默认 colSpan=1,不再错误地使用 column.colSpan 参与“行级”偏移计算,避免把表头或列级 colSpan 施加到所有行。和过往 review 建议一致,赞。
🧹 Nitpick comments (4)
src/hooks/useStickyOffsets.ts (4)
6-9
: 文档补充建议:明确 rowContext 的使用时机与性能影响建议在 JSDoc 中说明:仅当该“行”存在动态 colSpan=0(或其它动态合并)时才传入 rowContext;否则请传入 undefined 以避免不必要的 onCell 计算与 useMemo 重算。可加一行“当未提供 rowContext 时,行为与变更前保持一致”。
18-42
: 使左右两侧的累计更显式:按方向过滤 fixed=left/right(健壮性提升)当前实现用 column.fixed 的真值在 start/end 两次遍历中都做累加。假设列顺序始终为 [left][normal][right] 时是等价的,但可读性与对未来改动的鲁棒性较弱。建议按方向显式区分,仅在 start 时累加 fixed==='left',在 end 时累加 fixed==='right'。功能等价但意图更清晰,减少后续维护风险。
建议变更如下:
- const getOffsets = (startIndex: number, endIndex: number, offset: number) => { + const getOffsets = ( + startIndex: number, + endIndex: number, + step: number, + side: 'start' | 'end', + ) => { const offsets: number[] = []; let total = 0; - for (let i = startIndex; i !== endIndex; i += offset) { + for (let i = startIndex; i !== endIndex; i += step) { const column = flattenColumns[i]; offsets.push(total); - let colSpan = 1; - if (rowContext) { - const cellProps = column.onCell?.(rowContext.record, rowContext.rowIndex) || {}; - colSpan = cellProps.colSpan ?? 1; - } + let colSpan = 1; + if (rowContext) { + const cellProps = column.onCell?.(rowContext.record, rowContext.rowIndex) || {}; + colSpan = cellProps.colSpan ?? 1; + } - if (column.fixed && colSpan !== 0) { + const isLeft = column.fixed === 'left'; + const isRight = column.fixed === 'right'; + if ((side === 'start' ? isLeft : isRight) && colSpan !== 0) { total += colWidths[i] || 0; } } return offsets; }; @@ - const startOffsets = getOffsets(0, columnCount, 1); - const endOffsets = getOffsets(columnCount - 1, -1, -1).reverse(); + const startOffsets = getOffsets(0, columnCount, 1, 'start'); + const endOffsets = getOffsets(columnCount - 1, -1, -1, 'end').reverse();
16-36
: 减少 onCell 的重复调用:预计算本行的 colSpan 映射当前在 start 与 end 两次遍历中都会调用一次 column.onCell,导致每列每行计算两次。可在 useMemo 内(rowContext 存在时)预先生成 colSpanAt 数组,循环内直接索引,避免重复函数调用,尤其大列数/大数据量时更稳。
const stickyOffsets: StickyOffsets = useMemo(() => { const columnCount = flattenColumns.length; + // 仅当按行上下文存在时,预先计算每列在该行的 colSpan + const colSpanAt: number[] | undefined = rowContext + ? flattenColumns.map(col => { + const cellProps = col.onCell?.(rowContext.record, rowContext.rowIndex) || {}; + return cellProps.colSpan ?? 1; + }) + : undefined; + const getOffsets = (startIndex: number, endIndex: number, offset: number) => { const offsets: number[] = []; let total = 0; for (let i = startIndex; i !== endIndex; i += offset) { const column = flattenColumns[i]; offsets.push(total); - let colSpan = 1; - if (rowContext) { - const cellProps = column.onCell?.(rowContext.record, rowContext.rowIndex) || {}; - colSpan = cellProps.colSpan ?? 1; - } + const colSpan = colSpanAt ? colSpanAt[i] : 1; if (column.fixed && colSpan !== 0) { total += colWidths[i] || 0; } }备注:若采纳上条“按方向过滤”的建议,请将本段与之合并应用。
49-49
: 依赖数组建议去“对象壳”,仅依赖原子字段,降低无效重算依赖 rowContext(对象)会因调用方每次创建新对象而频繁失效。建议改为依赖 rowContext?.rowIndex 与 rowContext?.record(引用),以减少无意义的 useMemo 失效;当 record 引用变化时仍会正确重算。
- }, [colWidths, flattenColumns, rowContext]); + }, [colWidths, flattenColumns, rowContext?.rowIndex, rowContext?.record]);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
src/hooks/useStickyOffsets.ts
(3 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: bbb169
PR: react-component/table#1202
File: src/Table.tsx:903-904
Timestamp: 2024-11-08T12:53:09.293Z
Learning: 在 `src/Table.tsx` 文件的 React 组件 `Table` 中,即使 `bodyScrollLeft` 频繁更新,也需要在 `TableContextValue` 的 `useMemo` 依赖数组中包含 `bodyScrollLeft` 和 `headerCellRefs`,因为每次滚动时重新计算 `TableContextValue` 是解决该问题所必须的。
📚 Learning: 2024-11-08T12:53:09.293Z
Learnt from: bbb169
PR: react-component/table#1202
File: src/Table.tsx:903-904
Timestamp: 2024-11-08T12:53:09.293Z
Learning: 在 `src/Table.tsx` 文件的 React 组件 `Table` 中,即使 `bodyScrollLeft` 频繁更新,也需要在 `TableContextValue` 的 `useMemo` 依赖数组中包含 `bodyScrollLeft` 和 `headerCellRefs`,因为每次滚动时重新计算 `TableContextValue` 是解决该问题所必须的。
Applied to files:
src/hooks/useStickyOffsets.ts
🧬 Code graph analysis (1)
src/hooks/useStickyOffsets.ts (2)
src/interface.ts (1)
ColumnType
(118-133)src/index.ts (1)
ColumnType
(25-25)
🔇 Additional comments (2)
src/hooks/useStickyOffsets.ts (2)
23-24
: 局部变量 column 提升可读性把 flattenColumns[i] 提前赋值为 column 简化了多次访问,阅读性更好。
13-14
: 签名扩展校验通过
脚本检查结果显示:
- 只有在
src/Body/BodyRow.tsx
(第172–176行)按行场景下才会传入第三个rowContext
参数,且严格使用{ record, rowIndex }
。- 其余所有调用(例如
src/Table.tsx:384
)均为两参调用,不涉及第三参。无需调整,闭环。
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #1315 +/- ##
==========================================
- Coverage 96.18% 96.11% -0.08%
==========================================
Files 57 57
Lines 3408 3448 +40
Branches 620 630 +10
==========================================
+ Hits 3278 3314 +36
- Misses 125 129 +4
Partials 5 5 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
e317908
to
08a1a65
Compare
有问题重现么? |
这是一份复现的代码链接(demo),第1行0、1列合并后偏移位置不对 |
对于以下代码,当0、1列为固定列,且使用 onCell 进行表格列合并时,存在一个问题:
为此,我在bodyrow中动态去除了 colSpan=0列的宽度,修正了相关方法
Summary by CodeRabbit
新功能
修复
变更
测试