Skip to content

fix: cancel stale scroll retry sync#1498

Merged
zombieJ merged 1 commit into
masterfrom
agent/clear-scroll-retry-timeout
Jul 8, 2026
Merged

fix: cancel stale scroll retry sync#1498
zombieJ merged 1 commit into
masterfrom
agent/clear-scroll-retry-timeout

Conversation

@zombieJ

@zombieJ zombieJ commented Jul 8, 2026

Copy link
Copy Markdown
Member

Summary

  • Cancel pending scroll retry timers for a DOM target when a newer sync arrives.
  • Keep only the latest retry per target and clean pending retry timers on unmount.
  • Add a regression test for the case where the target already matches the latest scrollLeft.

Related

Follow-up to #1495.

Verification

  • node_modules/.bin/vitest run tests/Table.spec.jsx
  • npm run tsc
  • npm run lint
  • npm test

Summary by CodeRabbit

  • Bug Fixes

    • 修复了表格滚动同步时的延迟重试问题,避免旧的滚动位置在后续交互中误覆盖最新位置。
    • 提升了滚动行为的稳定性,减少了同一容器多次滚动时的异常跳变。
  • Tests

    • 新增滚动同步相关测试,覆盖过期重试定时器的取消与最新滚动状态保持。

@vercel

vercel Bot commented Jul 8, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
table Ready Ready Preview, Comment Jul 8, 2026 7:46am

@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 930e9775-d69a-4946-bc3d-a00a1b2888e1

📥 Commits

Reviewing files that changed from the base of the PR and between 7da1f76 and 8226a2d.

📒 Files selected for processing (2)
  • src/Table.tsx
  • tests/Table.spec.jsx

Walkthrough

Table 组件中引入 WeakMap 管理滚动容器的重试定时器,forceScroll 在设置新的延迟重试前会清理该元素已有的旧定时器,避免重复未清理的 setTimeout。新增测试用例验证过期重试不会覆盖已同步的 scrollLeft 值。

Changes

forceScroll 重试定时器修复

Layer / File(s) Summary
scrollRetryTimeoutMap 实现与测试
src/Table.tsx, tests/Table.spec.jsx
新增 WeakMap 缓存每个滚动容器元素的重试 setTimeout 句柄;forceScroll 在需要延迟重试前先清理该元素已有的旧定时器,避免重复且未清理的定时器;新增测试用例通过 fake timers 和可控 scrollLeft 验证目标已同步时不会执行过期重试覆盖新值。

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

  • react-component/table#1495: 同样修改 src/Table.tsxforceScroll/setTimeout 重试逻辑以防止过期的延迟 scrollLeft 写入,并调整 tests/Table.spec.jsx 中的相关断言。

Suggested reviewers: afc163

Poem

滚动条儿跑得欢,
旧定时器先清完,
WeakMap 记住谁的家,
不再乱写 scrollLeft 啦~
兔子蹦跳测试过,
🐇✨ 一切安然通过关!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 标题准确概括了本次修复的核心:取消过期的滚动重试同步。
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch agent/clear-scroll-retry-timeout

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.

@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown

React Doctor found 9 issues in 2 files · 9 warnings · score 77 / 100 (Needs work) · vs master

9 warnings

src/Table.tsx

  • ⚠️ L202 Large component is hard to read and change no-giant-component
  • ⚠️ L395 Missing effect dependencies exhaustive-deps
  • ⚠️ L395 Missing effect dependencies exhaustive-deps
  • ⚠️ L568 Missing effect dependencies exhaustive-deps
  • ⚠️ L578 Missing effect dependencies exhaustive-deps
  • ⚠️ L594 Missing effect dependencies exhaustive-deps
  • ⚠️ L640 Missing effect dependencies exhaustive-deps
  • ⚠️ L1012 Non-component export in component file only-export-components

tests/Table.spec.jsx

  • ⚠️ L1252 Component defined inside a component no-unstable-nested-components
⚠️ Warning: .github/workflows/react-doctor.yml is configured incorrectly. See below to fix.

React Doctor compares against master to report only the issues this pull request introduces. This run couldn't complete that comparison (usually a shallow CI checkout with no merge base), so it listed every issue in the changed files, including ones that already existed on master.

Add fetch-depth: 0 to the actions/checkout step in .github/workflows/react-doctor.yml so the checkout includes the history React Doctor needs:

 jobs:
   react-doctor:
     steps:
       - uses: actions/checkout@v5
+        with:
+          fetch-depth: 0

       - uses: millionco/react-doctor@v2

To silence this warning, set silence-missing-baseline-warning: true on the React Doctor action.

Reviewed by React Doctor for commit 8226a2d. See inline comments for fixes.

Comment thread src/Table.tsx Outdated

const [setScrollTarget, getScrollTarget] = useTimeoutLock(null);
const scrollRetryTimeoutRef = React.useRef(
new Map<HTMLDivElement, ReturnType<typeof setTimeout>>(),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

React Doctor · react-doctor/rerender-lazy-ref-init (warning)

useRef(new Map()) rebuilds this value on every render & throws it away.

Fix → Initialize the ref lazily so expensive values are not rebuilt and discarded on every render.

Docs

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a mechanism to cancel stale scrollLeft retry timeouts when the target is already synced, preventing unnecessary scroll updates. It also adds a corresponding unit test to verify this behavior. The review feedback suggests optimizing the initialization of scrollRetryTimeoutRef by using lazy initialization to avoid creating a new Map instance on every render.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread src/Table.tsx Outdated
Comment on lines +456 to +458
const scrollRetryTimeoutRef = React.useRef(
new Map<HTMLDivElement, ReturnType<typeof setTimeout>>(),
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Initializing useRef with new Map() directly in the render path causes a new Map instance to be created on every single render of the Table component, even though useRef only uses the initial value on the first render. Since Table can render frequently (e.g., during scrolling, resizing, or hovering), this leads to unnecessary object allocation and garbage collection overhead.

We can optimize this by using lazy initialization so that the Map is only created once on the initial render.

Suggested change
const scrollRetryTimeoutRef = React.useRef(
new Map<HTMLDivElement, ReturnType<typeof setTimeout>>(),
);
const scrollRetryTimeoutRef = React.useRef<Map<HTMLDivElement, ReturnType<typeof setTimeout>>>(null);
if (!scrollRetryTimeoutRef.current) {
scrollRetryTimeoutRef.current = new Map();
}

@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown

❌ Deploy failed

PR preview ❌ Failed ❌ Failed
🔗 Preview https://react-component-table-preview-pr-1498.surge.sh (may be unavailable)
📝 Commit8226a2d
🪵 LogsView logs
📋 Build log (last lines)
npm error     @eslint-community/eslint-utils@"^4.9.1" from @typescript-eslint/utils@8.63.0
npm error     node_modules/@typescript-eslint/utils
npm error       @typescript-eslint/utils@"8.63.0" from @typescript-eslint/eslint-plugin@8.63.0
npm error       node_modules/@typescript-eslint/eslint-plugin
npm error         peerOptional @typescript-eslint/eslint-plugin@"^8.0.0" from eslint-plugin-jest@29.15.4
npm error         node_modules/eslint-plugin-jest
npm error         1 more (typescript-eslint)
npm error       3 more (@typescript-eslint/type-utils, eslint-plugin-jest, typescript-eslint)
npm error     @eslint-community/eslint-utils@"^4.8.0" from eslint@10.6.0
npm error   10 more (@eslint/compat, @eslint/js, ...)
npm error
npm error Could not resolve dependency:
npm error peer eslint@"^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" from eslint-plugin-react@7.37.5
npm error node_modules/eslint-plugin-react
npm error   dev eslint-plugin-react@"^7.37.5" from the root project
npm error
npm error Conflicting peer dependency: eslint@9.39.4
npm error node_modules/eslint
npm error   peer eslint@"^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" from eslint-plugin-react@7.37.5
npm error   node_modules/eslint-plugin-react
npm error     dev eslint-plugin-react@"^7.37.5" from the root project
npm error
npm error Fix the upstream dependency conflict, or retry
npm error this command with --force or --legacy-peer-deps
npm error to accept an incorrect (and potentially broken) dependency resolution.
npm error
npm error
npm error For a full report see:
npm error /home/runner/.npm/_logs/2026-07-08T07_47_31_881Z-eresolve-report.txt
npm error A complete log of this run can be found in: /home/runner/.npm/_logs/2026-07-08T07_47_31_881Z-debug-0.log

🤖 Powered by surge-preview

@codecov

codecov Bot commented Jul 8, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.05%. Comparing base (7da1f76) to head (8226a2d).
⚠️ Report is 1 commits behind head on master.

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #1498   +/-   ##
=======================================
  Coverage   99.04%   99.05%           
=======================================
  Files          45       45           
  Lines        1362     1369    +7     
  Branches      409      410    +1     
=======================================
+ Hits         1349     1356    +7     
  Misses         13       13           

☔ View full report in Codecov by Harness.
📢 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.

@zombieJ zombieJ force-pushed the agent/clear-scroll-retry-timeout branch from 7023930 to 8226a2d Compare July 8, 2026 07:46
@zombieJ zombieJ marked this pull request as ready for review July 8, 2026 07:56
@zombieJ zombieJ merged commit dd5b7c3 into master Jul 8, 2026
13 of 14 checks passed
@zombieJ zombieJ deleted the agent/clear-scroll-retry-timeout branch July 8, 2026 07:58
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.

1 participant