React query and react context conversion#786
Conversation
|
Thanks for the pull request, @jacobo-dominguez-wgu! This repository is currently maintained by Once you've gone through the following steps feel free to tag them in a comment and let them know that your changes are ready for engineering review. 🔘 Get product approvalIf you haven't already, check this list to see if your contribution needs to go through the product review process.
🔘 Provide contextTo help your reviewers and other members of the community understand the purpose and larger context of your changes, feel free to add as much of the following information to the PR description as you can:
🔘 Get a green buildIf one or more checks are failing, continue working on your changes until this is no longer the case and your build turns green. DetailsWhere can I find more information?If you'd like to get more details on all aspects of the review process for open source pull requests (OSPRs), check out the following resources: When can I expect my changes to be merged?Our goal is to get community contributions seen and reviewed as efficiently as possible. However, the amount of time that it takes to review and merge a PR can vary significantly based on factors such as:
💡 As a result it may take up to several weeks or months to complete a review and merge your PR. |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #786 +/- ##
==========================================
+ Coverage 97.54% 98.19% +0.64%
==========================================
Files 148 145 -3
Lines 1302 1382 +80
Branches 225 297 +72
==========================================
+ Hits 1270 1357 +87
+ Misses 31 25 -6
+ Partials 1 0 -1 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
25d3bf6 to
983f04e
Compare
983f04e to
edac99f
Compare
Thanks @arbrandes, I have addressed this set of comments, I used a different approach from your suggestion for using the |
arbrandes
left a comment
There was a problem hiding this comment.
Thanks! A few more things in the comments.
(Apologies this is taking so many review passes. It's not reflective of the quality of your code, but rather on the size and importance of the refactor.)
src/containers/CourseCard/components/CourseCardBanners/CertificateBanner.jsx
Outdated
Show resolved
Hide resolved
No problem, I appreciate you take the time to review and find this details before it get merged. |
|
|
||
| const openSessionModal = reduxHooks.useUpdateSelectSessionModalCallback(cardId); | ||
| } = useEntitlementInfo(courseData); | ||
| const updateSelectSessionModal = useSelectSessionModal(); |
There was a problem hiding this comment.
The fix is simple:
| const updateSelectSessionModal = useSelectSessionModal(); | |
| const { updateSelectSessionModal } = useSelectSessionModal(); |
But I'm concerned that no unit test caught this. I think we're either over-mocking, or there's no unit test for this code path. Mind fixing the test up as well?
There was a problem hiding this comment.
There was not specific unit test for this path, I have added it.
arbrandes
left a comment
There was a problem hiding this comment.
A couple of minor things.
src/containers/Dashboard/index.jsx
Outdated
|
|
||
| export const Dashboard = () => { | ||
| hooks.useInitializeDashboard(); | ||
| const { data, isFetching } = useInitializeLearnerHome(); |
There was a problem hiding this comment.
I think we want isPending instead of isFetching, here. We only want the loading spinner during initial load, not afterwards.
| sortBy, | ||
| pageNumber, | ||
| ); | ||
| }, [data, filters, sortBy, pageNumber]); |
There was a problem hiding this comment.
This is a minor thing, but the old Redux code would reset the pagenumber after loading data, and it seems we're not doing that anymore. The problem is the classic one: if a user removes the last item from a list, and that happens to be the only item on the page they're on, they're going to see an empty list until they manually navigate to another page.
But instead of doing it at the mutation layer, I suggest you clamp the page number right here:
| }, [data, filters, sortBy, pageNumber]); | |
| }, [data, filters, sortBy, pageNumber]); | |
| // Clamp page number when filtered/mutated list shrinks | |
| React.useEffect(() => { | |
| if (numPages > 0 && pageNumber > numPages) { | |
| setPageNumber(1); | |
| } | |
| }, [numPages, pageNumber, setPageNumber]); |
If you could add a test for this, it would be great. Thank you!
There was a problem hiding this comment.
Applied, thanks.
src/data/hooks/mutationHooks.ts
Outdated
| }); | ||
| }; | ||
|
|
||
| const useLogShare = () => useMutation({ |
There was a problem hiding this comment.
It seems we're not actually using this hook anywhere. SocialShareMenu uses a different codepath.
This implementation looks better (there's some error catching), but I leave it up to you to decide whether we remove it, or actual use it in SocialShareMenu.
There was a problem hiding this comment.
I noticed it was not being used and forgot to remove it, doing it now.
src/data/hooks/queryKeys.ts
Outdated
| updateEntitlementEnrollment: () => [...learnerDashboardQueryKeys.all, 'updateEntitlementEnrollment'] as const, | ||
| deleteEntitlementEnrollment: () => [...learnerDashboardQueryKeys.all, 'deleteEntitlementEnrollment'] as const, | ||
| updateEmailSettings: () => [...learnerDashboardQueryKeys.all, 'updateEmailSettings'] as const, | ||
| logShare: () => [...learnerDashboardQueryKeys.all, 'logShare'] as const, |
There was a problem hiding this comment.
Missed a spot:
| logShare: () => [...learnerDashboardQueryKeys.all, 'logShare'] as const, |
| onSuccess: (data) => { | ||
| setRequestData(data); |
There was a problem hiding this comment.
In this case, onSuccess receives a response object, not response.data.
| onSuccess: (data) => { | |
| setRequestData(data); | |
| onSuccess: (response) => { | |
| setRequestData(response.data); |
There used to be an assertion that tested this, but it was removed.
There was a problem hiding this comment.
Fixed. Also modernized the test file to use renderHook and cover the removed assertion.
arbrandes
left a comment
There was a problem hiding this comment.
Alright, I think this is good to go! Thanks again!
Can you please rebase on master, though?
Description
This PR implements a migration from Redux to React Query and React Context.
This modernizes state management while maintaining all existing functionality.
All the redux code and files were removed, including all redux and related packages.
The folder and files structure for react query hooks and context were refactored.
Also includes a small refactor on the api files.
It closes #769
It closes #770
Part of react query migration initiative: #768
What Changed
Replaced Redux with React Query for server state management (API calls, caching)
Added React Context for client-side state (Pagination, filters, masquerading, course list back up)
Maintained backward compatibility with existing component interfaces
Created new apiHooks.ts with React Query hooks for all data operations
New Context Providers
FiltersProvider: Course filtering and pagination state
MasqueradeProvider: Admin masquerade functionality
SelectSessionProvider: Entitlement session selection
BackedDataProvider: Backup data for masquerade error handling
Component Updates
Updated all components, containers and hooks to use React Query hooks instead of Redux selectors
All tests were updated to work with the new state management system
Packages removed:
Context and react query folders after the refactor:
src/ └── data/ │ ├── constants/ # Application constants │ ├── context/ # React Context providers │ ├── index.tsx # Context exports │ ├── index.test.tsx # Context tests │ ├── BackedDataProvider.tsx # Backed data context │ ├── BackedData.test.tsx # Backed data tests │ ├── FiltersProvider.tsx # Filters state context │ ├── Filters.test.tsx # Filters tests │ ├── MasqueradeProvider.tsx # Masquerade context │ ├── Masquerade.test.tsx # Masquerade tests │ ├── SelectSessionProvider.tsx # Session selection context │ └── SelectSession.test.tsx # Session selection tests │ ├── hooks/ # React query hooks │ ├── index.ts # Hooks exports │ ├── queryHooks.ts # React Query hooks │ ├── queryHooks.test.tsx # Query hooks tests │ ├── mutationHooks.ts # React Query mutations │ ├── mutationHooks.test.tsx # Mutation hooks tests │ └── queryKeys.ts # React Query key definitions │ └── services/ # External service integrations │ ├── lms/ # Learning Management System │ ├── index.js # LMS service exports │ ├── api.ts # LMS API client │ ├── api.test.tsx # LMS API tests │ └── segment/ # Analytics/Segment integrationMigration Strategy
Phase 1: Update Dependencies (does not apply)Phase 2 (This PR): Add React Query + Context alongside Redux
Phase 3 (
#792Now also included on this PR): Remove all Redux related code and tests and refactor data folder structureHow to test it
Make sure all existing features work as before:
Dashboard Loading: Verify courses load correctly on initial page load and the fallback screen when there are no courses.
Course Filtering: Test search, status filters, and sorting functionality.
Course Card and Actions: Test unenroll, social sharing, email settings, entitlement, banners shows correctly.
Masquerade Feature: Test admin masquerade functionality with valid/invalid users.
Select session modal: I could not test it using the UI, but unit test passes (Manual testing required here).