Skip to content

fix: inline dead loop#78

Merged
zombieJ merged 1 commit intomasterfrom
inline
Apr 22, 2025
Merged

fix: inline dead loop#78
zombieJ merged 1 commit intomasterfrom
inline

Conversation

@zombieJ
Copy link
Member

@zombieJ zombieJ commented Apr 22, 2025

修复 inline 模式下的滚动锁死问题,另外 jsdom 模拟不出来这个效果。要到 antd 里再测一遍。

Summary by CodeRabbit

  • Bug Fixes
    • 修复了在启用内联模式(inlineMode)时页面会自动滚动的问题,提升了用户体验。

@vercel
Copy link

vercel bot commented Apr 22, 2025

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

Name Status Preview Comments Updated (UTC)
tour ✅ Ready (Inspect) Visit Preview 💬 Add feedback Apr 22, 2025 11:05am

@coderabbitai
Copy link

coderabbitai bot commented Apr 22, 2025

Walkthrough

本次更改调整了滚动到目标元素的逻辑。现在,只有在 inlineMode 为 false、目标元素不在视口中且 open 为 true 时,才会触发滚动操作。这样可以避免在启用 inlineMode 时自动滚动到目标元素。

Changes

文件路径 变更摘要
src/hooks/useTarget.ts 修改了滚动条件,增加了对 inlineMode 的判断,避免在启用 inlineMode 时滚动到目标元素。

Poem

🐇
小兔跳跃代码间,
inline 模式静悄悄,
滚动逻辑巧更改,
元素不再随意跑。
视口之外才滚动,
体验升级乐淘淘!

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.

src/hooks/useTarget.ts

Oops! Something went wrong! :(

ESLint: 7.32.0

ESLint couldn't find the plugin "eslint-plugin-react".

(The package "eslint-plugin-react" was not found when loaded as a Node module from the directory "".)

It's likely that the plugin isn't installed correctly. Try reinstalling by running the following:

npm install eslint-plugin-react@latest --save-dev

The plugin "eslint-plugin-react" was referenced from the config file in ".eslintrc.js » /node_modules/.pnpm/@umijs+fabric@2.14.1/node_modules/@umijs/fabric/dist/eslint.js".

If you still can't figure out the problem, please stop by https://eslint.org/chat/help to chat with the team.

✨ Finishing Touches
  • 📝 Generate Docstrings

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
🪧 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.
  • @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.

@github-actions
Copy link

github-actions bot commented Apr 22, 2025

😭 Deploy PR Preview f859b69 failed. Build logs

🤖 By surge-preview

@codecov
Copy link

codecov bot commented Apr 22, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 99.04%. Comparing base (d14b1c3) to head (f859b69).

Additional details and impacted files
@@           Coverage Diff           @@
##           master      #78   +/-   ##
=======================================
  Coverage   99.04%   99.04%           
=======================================
  Files           9        9           
  Lines         209      209           
  Branches       95       95           
=======================================
  Hits          207      207           
  Misses          2        2           

☔ 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

🧹 Nitpick comments (5)
src/hooks/useTarget.ts (5)

44-79: 建议:考虑提取滚动相关的逻辑到单独的函数中

updatePos函数处理了几个不同的职责:确定是否需要滚动、获取目标元素位置、处理内联模式的位置调整等。为了提高代码可维护性,建议将滚动逻辑提取到一个单独的函数中。

const updatePos = useEvent(() => {
  if (targetElement) {
    // 提取滚动逻辑到单独函数
+   const scrollIfNeeded = () => {
+     if (!inlineMode && !isInViewPort(targetElement) && open) {
+       targetElement.scrollIntoView(scrollIntoViewOptions);
+     }
+   };
+   
+   scrollIfNeeded();
-   if (!inlineMode && !isInViewPort(targetElement) && open) {
-     targetElement.scrollIntoView(scrollIntoViewOptions);
-   }

    const { left, top, width, height } =
      targetElement.getBoundingClientRect();
    // ... 剩余代码保持不变

84-95: 建议:优化事件监听器的性能

目前scrollresize事件没有节流(throttle)处理,在快速滚动或调整窗口大小时可能导致性能问题。建议添加节流来限制更新频率。

+ import throttle from '@rc-component/util/lib/hooks/useThrotte';
// 或者创建一个简单的节流函数
+ const throttle = (fn, delay) => {
+   let lastCall = 0;
+   return function(...args) {
+     const now = new Date().getTime();
+     if (now - lastCall < delay) {
+       return;
+     }
+     lastCall = now;
+     return fn(...args);
+   };
+ };

useLayoutEffect(() => {
+  const throttledUpdatePos = throttle(updatePos, 100); // 100ms的节流
  updatePos();
  // 更新时使用节流函数
- window.addEventListener('resize', updatePos);
- window.addEventListener('scroll', updatePos);
+ window.addEventListener('resize', throttledUpdatePos);
+ window.addEventListener('scroll', throttledUpdatePos);
  return () => {
-   window.removeEventListener('resize', updatePos);
-   window.removeEventListener('scroll', updatePos);
+   window.removeEventListener('resize', throttledUpdatePos);
+   window.removeEventListener('scroll', throttledUpdatePos);
  };
}, [targetElement, open, updatePos]);

87-94: 建议:使用useEventListener或类似工具来管理事件监听

对于事件监听的添加和移除,可以考虑使用useEventListener这样的钩子来简化代码并减少重复。


38-42: 注意:无依赖项的useLayoutEffect可能引起不必要的重渲染

这个useLayoutEffect钩子没有依赖数组,意味着它会在每次组件渲染后执行。建议添加适当的依赖项,例如[target],只在target改变时更新targetElement

- useLayoutEffect(() => {
+ useLayoutEffect(() => {
  const nextElement =
    typeof target === 'function' ? (target as any)() : target;
  setTargetElement(nextElement || null);
- });
+ }, [target]);

69-74: 建议:使用对象比较而非JSON.stringify

使用JSON.stringify比较对象结构是低效的,并且可能在处理包含特殊值(如循环引用)的对象时失败。建议使用深度比较函数或者直接比较各个属性。

setPosInfo(origin => {
-  if (JSON.stringify(origin) !== JSON.stringify(nextPosInfo)) {
+  if (!origin || 
+      origin.left !== nextPosInfo.left || 
+      origin.top !== nextPosInfo.top || 
+      origin.width !== nextPosInfo.width || 
+      origin.height !== nextPosInfo.height) {
    return nextPosInfo;
  }
  return origin;
});
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between d14b1c3 and f859b69.

📒 Files selected for processing (1)
  • src/hooks/useTarget.ts (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/hooks/useTarget.ts (1)
src/util.ts (1)
  • isInViewPort (3-10)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: preview

if (targetElement) {
// Exist target element. We should scroll and get target position
if (!isInViewPort(targetElement) && open) {
if (!inlineMode && !isInViewPort(targetElement) && open) {
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

修复了内联模式下的无限滚动循环问题,很好的改动!

此更改通过添加!inlineMode条件解决了一个关键问题。在内联模式下,元素的位置计算与常规模式不同(相对于父元素计算),之前的代码在内联模式下也会尝试滚动元素到视图中,这可能导致:

  1. 滚动触发 ->
  2. 触发scroll事件 ->
  3. 再次执行updatePos ->
  4. 元素仍然"不在视口中"(因为inline模式计算方式不同)->
  5. 再次触发滚动

从而形成死循环。此修复正确地阻止了内联模式下的自动滚动行为。

@zombieJ zombieJ merged commit c937fa9 into master Apr 22, 2025
12 checks passed
@zombieJ zombieJ deleted the inline branch April 22, 2025 11:09
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