Avoid effect-driven renders in image preview dialog#2772
Draft
cursor[bot] wants to merge 5 commits into
Draft
Conversation
Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
Comment on lines
+50
to
+51
| const activeIndex = | ||
| imageCount > 0 ? (preview.index + navigationOffset + imageCount) % imageCount : preview.index; |
Contributor
There was a problem hiding this comment.
🔴 Critical chat/ExpandedImageDialog.tsx:50
When navigationOffset is negative and larger than imageCount, the modulo calculation (preview.index + navigationOffset + imageCount) % imageCount produces a negative activeIndex. For example, with imageCount = 3, preview.index = 0, and navigationOffset = -5, the result is -2, causing preview.images[-2] to be undefined and the component to return null unexpectedly.
- const activeIndex =
- imageCount > 0 ? (preview.index + navigationOffset + imageCount) % imageCount : preview.index;
+ const activeIndex =
+ imageCount > 0 ? (((preview.index + navigationOffset) % imageCount) + imageCount) % imageCount : preview.index;🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file apps/web/src/components/chat/ExpandedImageDialog.tsx around lines 50-51:
When `navigationOffset` is negative and larger than `imageCount`, the modulo calculation `(preview.index + navigationOffset + imageCount) % imageCount` produces a negative `activeIndex`. For example, with `imageCount = 3`, `preview.index = 0`, and `navigationOffset = -5`, the result is `-2`, causing `preview.images[-2]` to be `undefined` and the component to return `null` unexpectedly.
Evidence trail:
apps/web/src/components/chat/ExpandedImageDialog.tsx lines 48-70 (REVIEWED_COMMIT): `navigationOffset` state starts at 0 and is incremented/decremented without clamping (lines 53-61). The activeIndex calculation at line 50-51 adds only one `imageCount` before applying JS `%` remainder. JavaScript `%` preserves sign of dividend: `(-2) % 3 === -2`. With sufficient left-arrow presses, activeIndex becomes negative, `preview.images[negativeIndex]` is undefined, and line 70 returns null.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What Changed
ExpandedImageDialogeffect that mirrored the incoming preview prop into local state.useEffectEvent.Why
React Doctor flagged the dialog for prop-mirrored state and derived-state synchronization. The previous effect added an extra commit after the parent selected a different image preview. The new flow derives preview selection during render, avoids the sync effect, and keeps keyboard subscription logic isolated in a hook.
React Doctor verification:
src/components/chat/ExpandedImageDialog.tsxreporteduseState "preview" is mirrored from prop "initialPreview" via this effectplus related derived-state warnings.ExpandedImageDialog.tsxdiagnostics in the final React Doctor JSON scan.UI Changes
React Scan before/after recordings are included in this PR:
assets/react-scan/expanded-image-dialog-before.webmassets/react-scan/expanded-image-dialog-after.webmBoth recordings were captured with React Scan enabled against the same Vite harness and interaction sequence.
Checklist
Validation:
bun fmtbun lint(passes with existing warnings)bun typecheckNote
Avoid effect-driven renders in
ExpandedImageDialogby replacing synced state with a navigation offsetExpandedImageDialog, replacing them with anavigationOffsetvalue computed relative to the incomingpreviewprop.useExpandedImageDialogKeyboardShortcutshook usinguseEffectEventto avoid stale closures on Escape and Arrow key events.getExpandedImagePreviewIdentityKeyinExpandedImagePreview.tsxand applies it as a ReactkeyonExpandedImageDialoginChatView, so the dialog remounts when the selected image identity changes instead of syncing via effects.📊 Macroscope summarized b89ba06. 3 files reviewed, 1 issue evaluated, 0 issues filtered, 1 comment posted
🗂️ Filtered Issues