Skip to content

refactor: convert profile to react-query and remove Redux - #1407

Open
arbrandes wants to merge 1 commit into
masterfrom
arbrandes/react-query
Open

arbrandes wants to merge 1 commit into
masterfrom
arbrandes/react-query

Conversation

@arbrandes

@arbrandes arbrandes commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

Description

Replaces the Redux stack (redux, react-redux, redux-saga, redux-thunk, reselect and their dev tooling) with @tanstack/react-query. The account, preferences, certificates and country allow-list become per-resource queries, the saves and photo changes become mutations that patch the cache, and the shared form state (the open field, drafts, per-field errors, save status) moves to a React context. services.js is renamed to api.js, as in Learner Dashboard and Account. The QueryClientProvider in index.jsx is temporary: the frontend-base conversion (#1405) removes it in favor of the shell's.

This is the first PR in the stack described in #1246, done on the current codebase so it can be reviewed separately from the frontend-base conversion, as openedx/frontend-app-account#1468 was for Account.

A few behaviors change along the way. Errors the sagas used to rethrow, which cancelled the root saga so the page ignored every later action until a reload, are now contained: an account fetch that fails with anything but a 404 shows the error page instead of a spinner that never ends, and a save that fails without field errors resets the form. Opening or closing a field also clears the outcome of the last save, so a field error from a failed save no longer reappears when that field is reopened, and a field opened while another one still shows "Saved" starts clean rather than inheriting that state and losing its drafts to the reset the saga ran 300ms later. An unknown username renders the not-found page in place instead of navigating to /notfound. A rejected photo upload now shows the LMS's message; the alert for it existed but was never fed. After moving a legacy all_users account to per-field privacy, the account and preferences are refetched rather than kept as fetched. The five ProfilePage snapshots are replaced by behavior assertions, and the unused state.userAccount selector, disabledCountries, mock_data.js and the savingEditedBio fixture go without replacement.

Closes #1404.

LLM usage notice

Built with assistance from Claude.

@codecov

codecov Bot commented Sep 23, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.90511% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 87.17%. Comparing base (c2669f8) to head (5c773a8).
⚠️ Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
src/index.jsx 0.00% 1 Missing ⚠️
src/profile/data/hooks.js 98.43% 1 Missing ⚠️
src/profile/forms/SocialLinks.jsx 50.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1407      +/-   ##
==========================================
+ Coverage   81.17%   87.17%   +6.00%     
==========================================
  Files          51       47       -4     
  Lines         834      772      -62     
  Branches      240      219      -21     
==========================================
- Hits          677      673       -4     
+ Misses        150       95      -55     
+ Partials        7        4       -3     

☔ View full report in Codecov by Harness.
📢 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.

@arbrandes
arbrandes force-pushed the arbrandes/react-query branch 2 times, most recently from 80c1b92 to 3db6bf2 Compare September 23, 2026 12:26
Server state moves to per-resource queries, the shared form state (open
field, drafts, errors, save status) to a React context, and redux,
redux-saga, redux-thunk and reselect go away. The service module is
renamed to api.js, following Learner Dashboard and Account.

Closes #1404

Co-Authored-By: Claude <noreply@anthropic.com>
@arbrandes
arbrandes force-pushed the arbrandes/react-query branch from 3db6bf2 to 5c773a8 Compare September 23, 2026 12:32
@arbrandes

Copy link
Copy Markdown
Contributor Author

Self-review notes, three passes; every finding is fixed and folded into the commit.

First pass: the alert for a rejected photo upload outlived a successful "Remove photo", since it read the save mutation's error and nothing reset it (the delete handler now does). Also two context actions nothing called, a preferences cache merge without the guard the account merge has, no direct test for useDeleteProfilePhoto, a dead formId prop on Certificates, and a platform list duplicated between SocialLinks and derive.js.

Second pass: opening or closing a field left a failed save's saveState and errors in place, so the stale error reappeared when the field was reopened. The reducer now clears both, which made the saga's 300ms reset step a no-op, so the provider keeps a single close timer. The certificates branch of the edit mode had no caller once Certificates stopped being connected, and every field component was subscribing to the certificates query just to feed it.

Third pass: leftovers only. RESET_DRAFTS had no dispatcher, SAVE_FAILURE could never actually merge, useProfileData returned values the page already takes from the form context, and the description gained a sentence on the open/close change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

Convert to react-query

1 participant