ENG-3443: Fix selectUser selector memoization#7927
Conversation
Wrap selectUser with createSelector so it returns a stable reference when state.auth hasn't changed, eliminating the Redux console warning about unstable selector results. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
1 Skipped Deployment
|
Replace Form.useWatch([], form) + isFieldsTouched(true) with a direct watch on the usernameConfirmation field value. The previous approach had a vacuous-truth edge case where isFieldsTouched(true) could return true when no fields were registered yet, which was masked by unnecessary rerenders from the unmemoized selectUser. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Code Review
Clean, well-scoped PR. Two targeted fixes with no production risk.
auth.slice.ts — selectUser memoization
The root cause diagnosis is correct: spreading { ...user, isRootUser } in a plain selector always produces a new object reference, which RTK's selector stability check rightfully flags. Wrapping with createSelector is the right fix — the memoized result is returned unchanged as long as state.auth hasn't changed.
One minor note on the input selector granularity (see inline comment): using selectAuth means the selector recomputes on any auth change (including token), not just user changes. Not a functional issue given login/logout change both atomically, but worth knowing.
DeleteUserModal.tsx — Form.useWatch targeting
Both changes are improvements:
- Watching only
"usernameConfirmation"instead of all fields ([]) is more targeted. - The disabled condition change from
!form.isFieldsTouched(true)→!usernameConfirmationis more semantically accurate for this UX (enable the button when text is present, not merely when the field has been touched).
One observation about form.getFieldsError() in the disabled expression (see inline comment) — benign for the current single-field form, but worth keeping in mind if the form grows.
Changelog
Changelog entry is present and accurate. ✅
🔬 Codegraph: unavailable
💡 Write /code-review in a comment to re-run this review.
Ticket ENG-3443
Description Of Changes
The
selectUserRedux selector inauth.slice.tswas a plain function that created a new object ({ ...user, isRootUser }) on every call. Since the returned object was referentially different each time, Redux flagged it as an unstable selector, logging a console warning and causing unnecessary rerenders in every component that consumes it (ProtectedRoute, AccountDropdownMenu, ManualTasks, MonitorList, etc.).This PR wraps
selectUserwithcreateSelectorfrom@reduxjs/toolkitso the result is memoized and only recomputes whenstate.authchanges.Code Changes
selectUserselector usingcreateSelectorwithselectAuthas its input selectorcreateSelectorto the@reduxjs/toolkitimportSteps to Confirm
npm run devinclients/admin-ui/)Pre-Merge Checklist
CHANGELOG.mdupdated