[codex] fix useLockFocus retry when element is filled later#748
[codex] fix useLockFocus retry when element is filled later#748
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Walkthrough更新了 Changes
Sequence Diagram(s)sequenceDiagram
participant Component
participant useRetryEffect
participant State as State (retryMark)
participant Ref as Ref (getElementRef)
participant DOM
Component->>useRetryEffect: 调用 useRetryEffect(lockEffect, [id, lock])
rect rgba(100, 150, 200, 0.5)
Note over useRetryEffect,DOM: 首次效果周期
useRetryEffect->>Ref: 读取 getElementRef.current()
Ref->>DOM: 尝试获取目标元素
DOM-->>Ref: 元素缺失 (undefined)
Ref-->>useRetryEffect: 返回 ready: false
useRetryEffect->>State: 更新 retryMark 触发重新渲染
end
rect rgba(100, 200, 150, 0.5)
Note over useRetryEffect,DOM: 重试效果周期
useRetryEffect->>Ref: 读取更新后的 getElementRef.current()
Ref->>DOM: 尝试获取目标元素
DOM-->>Ref: 元素存在
Ref-->>useRetryEffect: 返回 ready: true
useRetryEffect->>Component: 调用 lockFocus(...) 锁定焦点
useRetryEffect->>Component: 完成,停止重试
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #748 +/- ##
==========================================
+ Coverage 86.31% 86.42% +0.11%
==========================================
Files 39 39
Lines 1052 1068 +16
Branches 372 388 +16
==========================================
+ Hits 908 923 +15
- Misses 142 143 +1
Partials 2 2 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Code Review
This pull request introduces a useRetryEffect hook to handle scenarios where DOM elements are not immediately available for focus locking. The useLockFocus hook has been refactored to utilize this retry mechanism, and a new test case verifies that focus is correctly applied even if the target element appears after the initial render. Review feedback suggests increasing the hardcoded retry limit to better support asynchronous state updates and notes that spreading dependencies in the useEffect hook bypasses static analysis linting rules.
There was a problem hiding this comment.
🧹 Nitpick comments (2)
tests/focus.test.tsx (1)
127-129: 建议补充“聚焦外部元素后被拉回”的断言(增强锁定语义)当前只验证了最终会聚焦到容器。可再补一条外部按钮聚焦后的断言,确认延迟场景下锁定行为也生效。
可选补充断言(示例)
await waitFor(() => { expect(document.activeElement).toBe(focusContainer); }); + + const outerButton = getByTestId('outer-button') as HTMLButtonElement; + outerButton.focus(); + expect(document.activeElement).toBe(focusContainer);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/focus.test.tsx` around lines 127 - 129, Add an extra assertion that verifies an external element's focus is immediately pulled back to the locked container: after focusing the outside button (simulate focus on the outside button element used in the test), assert that document.activeElement is not the external button and instead becomes focusContainer (in addition to the existing waitFor that ensures final focus). Locate the spot near the existing waitFor/expect using waitFor, document.activeElement and focusContainer and add the external-button-focus then assert it gets redirected back to focusContainer to strengthen lock semantics.src/Dom/focus.ts (1)
275-275: 重试上限硬编码为 1 次,建议提升为可配置常量Line 275 在第二次尝试后就停止重试;如果元素在更晚的异步阶段才出现,仍可能锁定失败。建议改为可配置上限(或至少使用命名常量),减少边界场景遗漏。
可选改法(示例)
+const LOCK_FOCUS_MAX_RETRY = 5; + const lockEffect = (retryTimes: number): RetryEffectResult => { if (!lock) { return [undefined, true]; } const element = getElementRef.current(); if (element) { return [lockFocus(element, id), true]; } - return [undefined, retryTimes >= 1]; + return [undefined, retryTimes >= LOCK_FOCUS_MAX_RETRY]; };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/Dom/focus.ts` at line 275, The return currently hard-codes the retry limit via "retryTimes >= 1", which stops after one retry; change this to use a named constant or configurable parameter (e.g., MAX_RETRIES or a function arg maxRetries) instead of the literal 1 so the limit is adjustable; update the code that reads/updates retryTimes and the call sites to pass/configure the new maxRetries (or import the constant) and replace the condition "retryTimes >= 1" with "retryTimes >= MAX_RETRIES" (or the param name) to make retries configurable and avoid the hard-coded boundary.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@src/Dom/focus.ts`:
- Line 275: The return currently hard-codes the retry limit via "retryTimes >=
1", which stops after one retry; change this to use a named constant or
configurable parameter (e.g., MAX_RETRIES or a function arg maxRetries) instead
of the literal 1 so the limit is adjustable; update the code that reads/updates
retryTimes and the call sites to pass/configure the new maxRetries (or import
the constant) and replace the condition "retryTimes >= 1" with "retryTimes >=
MAX_RETRIES" (or the param name) to make retries configurable and avoid the
hard-coded boundary.
In `@tests/focus.test.tsx`:
- Around line 127-129: Add an extra assertion that verifies an external
element's focus is immediately pulled back to the locked container: after
focusing the outside button (simulate focus on the outside button element used
in the test), assert that document.activeElement is not the external button and
instead becomes focusContainer (in addition to the existing waitFor that ensures
final focus). Locate the spot near the existing waitFor/expect using waitFor,
document.activeElement and focusContainer and add the external-button-focus then
assert it gets redirected back to focusContainer to strengthen lock semantics.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 0a7362d3-f496-4405-9a05-15d60eeb1f1c
📒 Files selected for processing (2)
src/Dom/focus.tstests/focus.test.tsx
Summary
useRetryEffecthelper insrc/Dom/focus.tsto retry an effect until a late-filled element becomes availableuseLockFocusto use that retry flow so locking still starts when the target ref is populated via a later state updateWhy
useLockFocuspreviously only retried when[lock, id]changed. If the target element was filled by a later state update, the initial effect could miss the element and never lock focus.Impact
Components that provide the lock target through a state-backed ref now still get focus locking after the element appears.
Validation
npx tsc --noEmitnpx eslint src/Dom/focus.ts tests/focus.test.tsxnpm test -- tests/focus.test.tsx --runInBandSummary by CodeRabbit
发布说明
错误修复
测试