Skip to content
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

enhance: Scroll top should not shaking #296

Merged
merged 4 commits into from
Jan 3, 2025
Merged

enhance: Scroll top should not shaking #296

merged 4 commits into from
Jan 3, 2025

Conversation

zombieJ
Copy link
Member

@zombieJ zombieJ commented Jan 3, 2025

ref ant-design/ant-design#52121

Note: jsdom 下无法对该行为进行模拟

Summary by CodeRabbit

  • 新功能

    • 改进了列表滚动时的高度同步机制
    • 优化了高度收集的异步处理方式
  • 性能优化

    • 移除了 requestAnimationFrame 依赖
    • 引入基于 Promise 的高度收集方法
    • 增强了缓存键值变更追踪能力
  • Bug 修复

    • 修复了滚动时可能出现的位置跳跃问题
    • 改善了首个可见项目高度变化时的滚动同步

Copy link

vercel bot commented Jan 3, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
virtual-list ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jan 3, 2025 7:07am

Copy link

coderabbitai bot commented Jan 3, 2025

Warning

There were issues while running some tools. Please review the errors and either fix the tool’s configuration or disable the tool if it’s a critical failure.

🔧 eslint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

examples/basic.tsx

Oops! Something went wrong! :(

ESLint: 8.57.1

Error: Cannot read config file: /.eslintrc.js
Error: Cannot find module '@umijs/fabric/dist/eslint'
Require stack:

  • /.eslintrc.js
  • /node_modules/.pnpm/@eslint[email protected]/node_modules/@eslint/eslintrc/dist/eslintrc.cjs
  • /node_modules/.pnpm/[email protected]/node_modules/eslint/lib/cli-engine/cli-engine.js
  • /node_modules/.pnpm/[email protected]/node_modules/eslint/lib/eslint/eslint.js
  • /node_modules/.pnpm/[email protected]/node_modules/eslint/lib/eslint/index.js
  • /node_modules/.pnpm/[email protected]/node_modules/eslint/lib/cli.js
  • /node_modules/.pnpm/[email protected]/node_modules/eslint/bin/eslint.js
    at Module._resolveFilename (node:internal/modules/cjs/loader:1248:15)
    at Module._load (node:internal/modules/cjs/loader:1074:27)
    at TracingChannel.traceSync (node:diagnostics_channel:315:14)
    at wrapModuleLoad (node:internal/modules/cjs/loader:217:24)
    at Module.require (node:internal/modules/cjs/loader:1339:12)
    at require (node:internal/modules/helpers:135:16)
    at Object. (/.eslintrc.js:1:14)
    at Module._compile (node:internal/modules/cjs/loader:1546:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1691:10)
    at Module.load (node:internal/modules/cjs/loader:1317:32)

概述

演练

这次更改涉及虚拟列表组件的性能和滚动行为优化。主要修改包括在 useHeights 钩子中替换 requestAnimationFrame,使用基于 Promise 的方法管理高度收集。CacheMap 类新增了跟踪键变化的功能,并在 RawList 组件中添加了布局效果钩子,以同步滚动位置。

变更

文件 变更摘要
examples/basic.tsx 修改 MyItem 组件高度样式,注释滚动日志,添加挂载时滚动到极限索引的效果
src/List.tsx 新增 useLayoutEffect 钩子,同步首个可见项高度变化时的滚动位置
src/hooks/useHeights.tsx 移除 requestAnimationFrame,改用基于 Promise 的高度收集机制
src/utils/CacheMap.ts 新增 diffKeys 属性和 resetRecordgetRecord 方法以跟踪键变化

诗歌

🐰 虚拟列表,轻盈如风
高度追踪,智慧纷纷
Promise 代替 RAF 舞
滚动优雅,性能飞腾
兔子代码,跃动精灵!


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

codecov bot commented Jan 3, 2025

Codecov Report

Attention: Patch coverage is 70.83333% with 7 lines in your changes missing coverage. Please review.

Project coverage is 97.49%. Comparing base (42dd61e) to head (c568e8b).
Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
src/List.tsx 36.36% 7 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #296      +/-   ##
==========================================
- Coverage   98.32%   97.49%   -0.84%     
==========================================
  Files          19       19              
  Lines         778      799      +21     
  Branches      187      188       +1     
==========================================
+ Hits          765      779      +14     
- Misses         13       20       +7     

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

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 (3)
src/hooks/useHeights.tsx (1)

29-29: 以自增的方式替代原先 raf 取消逻辑。
通过 promiseIdRef.current += 1 来阻断上一次非同步流程,减少了对浏览器帧调度的依赖,但需确保在过多异步场景中不会导致过度频繁的 promiseIdRef 更新。

examples/basic.tsx (2)

13-14: 将动态高度改为固定 100 的实现可能掩盖部分真实场景。
在演示环境下此做法确实可简化,但若要测试不同高度对滚动的影响,仍需保留原来的动态逻辑或额外提供测试用例。


48-48: 注释掉 console.log 可减少调试输出,但请保持必要的日志。
若仍需观测滚动位置,建议改用可控的日志或埋点,以便排查滚动问题。

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 42dd61e and 636c04a.

📒 Files selected for processing (4)
  • examples/basic.tsx (3 hunks)
  • src/List.tsx (1 hunks)
  • src/hooks/useHeights.tsx (2 hunks)
  • src/utils/CacheMap.ts (1 hunks)
🔇 Additional comments (8)
src/utils/CacheMap.ts (3)

11-12: 在 CacheMap 中新增 diffKeys 属性的做法值得肯定。
此属性可以追踪键值变动,有助于后续渲染逻辑判定何时触发更新。


20-20: set 方法中将 key 加入 diffKeys 时,注意类型转换。
当前通过 key as string 转换类型后存储,若后续需要直接使用纯粹的 React.Key,请确保冲突情形(如数字型 key 与 string 同值)能正确排查。


27-37: 新增的 resetRecordgetRecord 方法能够有效管理并访问被修改的 key 列表。

  • resetRecord() 清空变动记录后,有助于在后续渲染或滚动同步时避免重复计算。
  • getRecord() 返回 Set<React.Key>,便于其他组件判断是否有变动。
src/hooks/useHeights.tsx (2)

25-26: 通过 useRef(new CacheMap())promiseIdRef 配合,简化了高度收集的管理。
heightsRef 中使用自定义容器可更灵活地跟踪高度变化,promiseIdRef 则在异步场景下有效区分多次更新。


59-65: 使用 Promise 的异步回调替代 requestAnimationFrame
此做法能保证只执行最新批次的高度收集逻辑,但仍需确认在某些低性能环境中是否存在丢帧或时序问题。若后续需要更流畅的视觉效果,或可考虑结合 requestIdleCallback 等手段。

examples/basic.tsx (1)

57-62: 使用 useEffect 在挂载时强制滚动到较大索引。
此做法可检验列表在极端索引下的渲染与滚动情况,但在手机端或性能弱的设备上可能有卡顿风险。
[approve]

src/List.tsx (2)

274-290: useLayoutEffect 中同步首个可见条目的真实高度,避免向上滚动时的跳动问题。

  • 逻辑仅限记录一处变动 (changedRecord.size === 1),若实际场景中第一可见条目同时发生多种变动,后续可能还需扩展。
  • 当真实高度与 itemHeight 不匹配时,通过 syncScrollTop 调整滚动位置能有效防止抖动。

291-293: 调用 heights.resetRecord() 清空变动记录。
此操作可防止重复侦测同一条目的高度变动,让后续渲染周期更精准。

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