fix(frontend): resolve set-state-in-effect in SettingsPage (#1063)#1074
fix(frontend): resolve set-state-in-effect in SettingsPage (#1063)#1074ericsocrat merged 1 commit intomainfrom
Conversation
Replaces useEffect that synced country/language state from useQuery prefs result with the React 19 'adjust state during render' pattern (https://react.dev/learn/you-might-not-need-an-effect#adjusting-some-state-when-a-prop-changes). A prevPrefs state tracks the last seen query result; when prefs identity changes, the new values are written before render completes. Behaviour is unchanged - the form still populates after the query resolves and after refetches.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📸 PR ScreenshotsCaptured 2 screenshots (1 mobile, 1 desktop) for 1 changed page(s):
📥 Download screenshots from workflow artifacts. Captured by PR Screenshots workflow • 2026-05-01 |
Bundle Size Report
✅ Bundle size is within acceptable limits. |
There was a problem hiding this comment.
Pull request overview
This PR removes a useEffect-based state sync in the Settings/Profile page to resolve the React Compiler set-state-in-effect warning by switching to the “adjust state during render when upstream data changes” pattern.
Changes:
- Replaced the
useEffect([prefs])that populatedcountry/languagefrom React Queryprefswith a render-time guarded sync usingprevPrefs. - Added inline documentation referencing the React “you might not need an effect” guidance.
| const [prevPrefs, setPrevPrefs] = useState(prefs); | ||
| if (prefs !== prevPrefs) { | ||
| setPrevPrefs(prefs); | ||
| if (prefs) { | ||
| setCountry(prefs.country ?? ""); | ||
| setLanguage((prefs.preferred_language ?? "en") as SupportedLanguage); | ||
| } |
There was a problem hiding this comment.
prevPrefs is initialized with prefs, so if React Query returns cached preferences on the first render (likely since RouteGuard already caches queryKeys.preferences), the if (prefs !== prevPrefs) branch will never run and country/language will stay at their default values. This is a behavioral regression vs the previous effect, which populated state even when prefs was available immediately. Consider initializing country/language from prefs via lazy useState initializers, or initialize prevPrefs to a sentinel (e.g., undefined) so the first non-undefined prefs triggers the sync.
…) (#1077) Phase 2 of #1063 -- resolves 2 of 19 violations (running total: 12/19 across 9 PRs). Two react-hooks/set-state-in-effect warnings in SearchAutocomplete.tsx resolved by adjusting state during render: 1. Refresh recent-searches list on dropdown open: replaced the show-dep useEffect with a prevShow render-phase tracker. Added a lazy initial-state initializer so the list is hydrated on mount when show is already true (preserves existing test contract). 2. Reset activeIndex when suggestions/query change: replaced the multi-dep useEffect with a composite resetKey + prevResetKey render-phase tracker. Pattern: https://react.dev/learn/you-might-not-need-an-effect#adjusting-some-state-when-a-prop-changes Behaviour unchanged. 32/32 vitest pass, eslint and tsc clean. Cross-references: #1067, #1069, #1070, #1071, #1072, #1073, #1074, #1075, #1076. Co-authored-by: ericsocrat <ericsocrat@users.noreply.github.com>
Phase 2 of #1063 - sixth PR, seventh violation of 19. Resolves
src/app/app/settings/page.tsx:57.Change
Replaces a
useEffectthat syncedcountry/languagestate from auseQueryprefsresult with the React 19 'adjust state during render' pattern (https://react.dev/learn/you-might-not-need-an-effect#adjusting-some-state-when-a-prop-changes).A
prevPrefsstate variable tracks the last seen query result; when theprefsreference changes, the new values are written before render completes.Behaviour is unchanged - the form still populates after the query resolves and after refetches.
Verification
eslint src/app/app/settings/page.tsx- cleanvitest run src/app/app/settings/page.test.tsx- 14/14 passtsc --noEmit- cleanProgress