Skip to content

Conversation

@li-jia-nan
Copy link
Member

@li-jia-nan li-jia-nan commented Sep 14, 2025

  1. 因为 ColGroup 是函数,内部可能依赖其它变量,所以移除 useMemo,避免闭包问题
  2. noData 的时候返回 null,而不是 ColGroup

Summary by CodeRabbit

  • 新功能
  • Bug 修复
    • 空数据或列宽无效时不再渲染列组,减少控制台警告与布局异常
  • 性能优化
    • 仅在存在数据且列宽有效时渲染列组,降低不必要渲染与计算
  • 重构
    • 精简列组渲染分支与依赖判断,简化控制流以提升稳定性与可维护性
  • 文档
    • 示例中改进 measureRow 渲染:当为有效 React 元素时克隆并合并样式以隐藏;非元素值不再被额外包裹,避免结构问题

@vercel
Copy link

vercel bot commented Sep 14, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
table Ready Ready Preview Comment Sep 15, 2025 3:33am

@coderabbitai
Copy link

coderabbitai bot commented Sep 14, 2025

Note

Other AI code review bot(s) detected

CodeRabbit 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

本次变更调整 FixedHolder 中 ColGroup 的渲染控制:以 mayBeEmpty 决定是否渲染 ColGroup,仅在存在数据且 mergedColumnWidth 有效时渲染;同时精简了 useMemo 依赖并移除之前的 colGroupNode 分支。示例代码 measureRowRender 的渲染包装逻辑也被条件化处理。

Changes

Cohort / File(s) Summary of Changes
FixedHolder ColGroup 渲染控制
src/FixedHolder/index.tsx
mayBeEmpty 替代原 colGroupNode 分支;仅在有数据且 mergedColumnWidth 有效时渲染 <ColGroup>(否则返回 null);移除对原始 ColGroup 的回退路径;精简 useMemo 依赖至 noDatamergedColumnWidth;保留 <ColGroup> props 结构(colWidths=[...mergedColumnWidth, combinationScrollBarSize]columCount+1columns=flattenColumnsWithScrollbar)。
measureRowRender 条件化包装
docs/examples/measureRowRender.tsx
将对 measureRow 的隐藏包装改为条件逻辑:若 measureRow 是有效的 React 元素则 clone 并合并样式以包含 display: 'none',否则直接返回原始值;保留 API 签名,无导出/声明更改。

Sequence Diagram(s)

sequenceDiagram
  participant Data as 输入 (noData, mergedColumnWidth)
  participant FixedHolder as FixedHolder
  participant ColGroup as ColGroup

  Note over Data,FixedHolder: FixedHolder 接收 noData 与 mergedColumnWidth
  Data-->>FixedHolder: 提供 noData, mergedColumnWidth
  Note over FixedHolder: 计算 mayBeEmpty = noData || !mergedColumnWidth

  alt mayBeEmpty = true
    FixedHolder--x ColGroup: 不渲染(返回 null)
  else mayBeEmpty = false
    FixedHolder->>ColGroup: 渲染 ColGroup\nprops: colWidths=[...mergedColumnWidth, combinationScrollBarSize]\ncolumCount+1, columns=flattenColumnsWithScrollbar
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • afc163
  • zombieJ

Poem

我是小兔轻跳来,
列宽齐整才现才,
无宽无数据我闭眼,
克隆样式悄悄藏,
渲染更简步更快。 🐰✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed 标题 “avoiding closure problems” 与本次 PR 的主要意图相关,因为更改的核心是为了解决 ColGroup 上 useMemo 导致的闭包问题并在无数据时不渲染 ColGroup,而标题表达了这一动机;但标题较为宽泛,未指明受影响的组件或代码位置,可能对快速浏览变更历史的同事不够明确。
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch renderColGroup-up

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0a8f306 and ab7bcad.

📒 Files selected for processing (1)
  • docs/examples/measureRowRender.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/examples/measureRowRender.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: test / react component workflow
  • GitHub Check: test / react component workflow

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a 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 @li-jia-nan, 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!

This pull request refactors the rendering mechanism for the ColGroup component within FixedHolder to address potential closure-related issues and enhance rendering efficiency. It extracts the complex conditional logic for ColGroup's presence into a dedicated memoized boolean, mayBeEmpty, which then drives the direct conditional rendering of the component, leading to a more predictable and optimized update cycle.

Highlights

  • Refactored ColGroup Rendering Logic: The logic for conditionally rendering the ColGroup component has been refactored to improve performance and avoid potential closure issues.
  • Introduced mayBeEmpty Memoized State: A new useMemo hook, mayBeEmpty, was introduced to encapsulate the boolean logic determining if the ColGroup should be rendered, based on data availability and column width validity.
  • Optimized useMemo Dependencies: By separating the conditional logic, the dependencies for the memoized boolean are now more focused, which helps prevent unnecessary re-renders of the ColGroup component.
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

  1. 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.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

这个 PR 将 useMemo 修改为了一个函数,这可能会导致性能问题。标题表明这是为了修复一个闭包问题,但原始的依赖项看起来是正确的。此外,这个修改没有修复一个已有的 bug,即返回了组件类型而不是组件实例。我建议恢复使用 useMemo 并修复潜在的 bug。

@codecov
Copy link

codecov bot commented Sep 14, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 96.10%. Comparing base (5599e70) to head (ab7bcad).
⚠️ Report is 1 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1352      +/-   ##
==========================================
- Coverage   96.11%   96.10%   -0.02%     
==========================================
  Files          57       57              
  Lines        3449     3437      -12     
  Branches      632      629       -3     
==========================================
- Hits         3315     3303      -12     
  Misses        129      129              
  Partials        5        5              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link

@coderabbitai coderabbitai bot left a 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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/FixedHolder/index.tsx (1)

90-121: 修复 FixedHolder 中 wheel 监听器的闭包陈旧(direction / onScroll)

当前 useEffect([]) 捕获了初始的 direction 与 onScroll,组件更新后事件仍会使用旧值。应使用 refs 保存最新回调与方向,保持监听器绑定稳定。

位置:src/FixedHolder/index.tsx(useEffect 注册 wheel 监听器,约 90–121 行)

   const scrollRef = React.useRef<HTMLDivElement>(null);
 
   const setScrollRef = React.useCallback((element: HTMLElement) => {
     fillRef(ref, element);
     fillRef(scrollRef, element);
   }, []);
 
+  // 保存最新 onScroll 与 direction,避免闭包陈旧
+  const onScrollRef = React.useRef(onScroll);
+  const directionRef = React.useRef(direction);
+  React.useEffect(() => {
+    onScrollRef.current = onScroll;
+  }, [onScroll]);
+  React.useEffect(() => {
+    directionRef.current = direction;
+  }, [direction]);
+
   React.useEffect(() => {
     function onWheel(e: WheelEvent) {
       const { currentTarget, deltaX } = e as unknown as React.WheelEvent<HTMLDivElement>;
       if (deltaX) {
         const { scrollLeft, scrollWidth, clientWidth } = currentTarget;
         const maxScrollWidth = scrollWidth - clientWidth;
         let nextScroll = scrollLeft + deltaX;
 
-        if (direction === 'rtl') {
+        if (directionRef.current === 'rtl') {
           nextScroll = Math.max(-maxScrollWidth, nextScroll);
           nextScroll = Math.min(0, nextScroll);
         } else {
           nextScroll = Math.min(maxScrollWidth, nextScroll);
           nextScroll = Math.max(0, nextScroll);
         }
 
-        onScroll({
+        onScrollRef.current({
           currentTarget,
           scrollLeft: nextScroll,
         });
         e.preventDefault();
       }
     }
 
     const scrollEle = scrollRef.current;
     scrollEle?.addEventListener('wheel', onWheel, { passive: false });
 
     return () => {
       scrollEle?.removeEventListener('wheel', onWheel);
     };
   }, []);

在切换 direction 或替换 onScroll 回调时,验证滚动行为是否与预期一致,确认未出现双绑或遗漏解绑。

🧹 Nitpick comments (1)
src/FixedHolder/index.tsx (1)

160-162: 注释与实现不一致,容易误导维护者

注释写的是“无数据或无列宽时使用 original ColGroup”,但实现是直接不渲染。若保留当前实现,请同步更新注释,或恢复对应的回退逻辑,避免后续阅读者产生误解。

建议更新为:

- // use original ColGroup if no data or no calculated column width, otherwise use calculated column width
- // Return original colGroup if no data, or mergedColumnWidth is empty, or all widths are falsy
+ // 仅在「无数据 ∧ 未计算到列宽 ∧ 不存在滚动条列」时跳过渲染 ColGroup;
+ // 其余情况渲染,以保证滚动条列与 sticky/fixed 布局的对齐稳定性。
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a6ca532 and 05c1ed2.

📒 Files selected for processing (1)
  • src/FixedHolder/index.tsx (2 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 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` 是解决该问题所必须的。
🔇 Additional comments (1)
src/FixedHolder/index.tsx (1)

190-196: 在空数据但存在固定列/滚动条时仍渲染 ,并校验 colWidths 长度一致

文件:src/FixedHolder/index.tsx 行 ~190-196

  • 当前仅在 !mayBeEmpty 时渲染 ,会在“空数据 + sticky/fixed/滚动条列”场景缺失 ,导致列对齐/滚动条列宽异常。修改 mayBeEmpty 判定或在存在固定列/滚动条时强制渲染 。
  • 确认 columCount + 1 与 colWidths = [...mergedColumnWidth, combinationScrollBarSize] 在所有分支长度一致;若不一致,修正列计数或 colWidths 构造逻辑以保证一一对应。

Copy link

@coderabbitai coderabbitai bot left a 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 (1)
src/interface.ts (1)

156-159: 微优化:React.FC<P>React.ComponentType<P> 存在重叠

React.FC<P> 本质可赋值给 React.ComponentType<P>,保留两者略显冗余。可按需精简(不影响行为)。

可选精简:

 type Component<P> =
   | React.ComponentType<P>
   | React.ForwardRefExoticComponent<P>
-  | React.FC<P>
-  | keyof JSX.IntrinsicElements;
+  | keyof JSX.IntrinsicElements;
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 05c1ed2 and 771c7e8.

📒 Files selected for processing (2)
  • docs/demo/measureRowRender.md (1 hunks)
  • src/interface.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • docs/demo/measureRowRender.md
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: test / react component workflow
  • GitHub Check: test / react component workflow
🔇 Additional comments (2)
src/interface.ts (2)

156-161: AI 摘要与代码不一致,请确认是否有意移除 React.ReactHTML

摘要称“新增了 keyof React.JSX.IntrinsicElements”,但当前代码未见 keyof React.ReactHTML。如果旧版曾允许 HTML 标签键且你不想扩大到 SVG,可考虑继续保留或改为仅 HTML。请确认意图。


156-161: 建议:将 React.JSX.IntrinsicElements 替换为全局 JSX.IntrinsicElements;需验证 React/@types/react 版本与 tsconfig.jsx 配置

原因:React.JSX.IntrinsicElements 依赖较新 React 类型定义与 TS 配置,使用全局 JSX.IntrinsicElements 在更多 TS/React 组合下更兼容。上次校验脚本运行时出现 jq/路径解析噪音(node_modules 的 tsconfig),无法自动确认。运行下列修正脚本并粘贴输出以完成验证。

可选修正(仅类型层变动,不影响运行时):

 type Component<P> =
   | React.ComponentType<P>
   | React.ForwardRefExoticComponent<P>
-  | React.FC<P>
-  | keyof React.JSX.IntrinsicElements;
+  | React.FC<P>
+  | keyof JSX.IntrinsicElements;

修正校验脚本(在仓库根目录运行并粘贴输出):

#!/bin/bash
set -euo pipefail

if [ ! -f package.json ]; then
  echo "package.json not found in current directory"
  exit 0
fi

echo "React versions (dependencies / peerDependencies / devDependencies):"
jq -r '
  [ (.dependencies.react // empty),
    (.peerDependencies.react // empty),
    (.devDependencies.react // empty) ] |
  unique[]' package.json || true

echo
echo "@types/react versions (dependencies / peerDependencies / devDependencies):"
jq -r '
  [ (.dependencies["@types/react"] // empty),
    (.peerDependencies["@types/react"] // empty),
    (.devDependencies["@types/react"] // empty) ] |
  unique[]' package.json || true

echo
echo "tsconfig files (excluding node_modules) and jsx settings:"
find . -path './node_modules' -prune -o -type f -name 'tsconfig*.json' -print | while read -r f; do
  echo "==> $f"
  jq -r '.compilerOptions.jsx // "N/A", .compilerOptions.jsxImportSource // "N/A"' "$f" || true
done

echo
echo "Search for legacy React.ReactHTML usage (excluding node_modules/dist):"
rg -n --hidden 'React\.ReactHTML' --glob '!**/node_modules/**' --glob '!**/dist/**' || true

若不希望放宽到 SVG(例如在 table 语境下不期望 ),可改为只接受 HTML 标签键(参见下一条评论)。

!mergedColumnWidth.length ||
mergedColumnWidth.every(width => !width)
) {
return ColGroup;
Copy link
Member Author

@li-jia-nan li-jia-nan Sep 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ColGroup 是一个函数,直接渲染到 UI 会报错,这里应该返回 null

// 按照 html 规范,tr 的父元素必须是 table、thead、tbody、tfoot 标签,子元素必须是 th、td 标签
// 因此这里我们用一个 div 包裹是不对的,在控制台中会报错
const measureRowRender: TableProps['measureRowRender'] = measureRow => (
<div style={{ display: 'none' }}>{measureRow}</div>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

改成 tr 避免 warning

Copy link
Member Author

@li-jia-nan li-jia-nan Sep 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

不行,加什么都会报错,原本的 dom 结构就是刚刚好,我直接用 cloneElement 把 style 传进去了

@afc163 afc163 merged commit 3efc943 into master Sep 15, 2025
13 checks passed
@afc163 afc163 deleted the renderColGroup-up branch September 15, 2025 04:00
This was referenced Sep 15, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants