-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Fix external auth buttons in React Strict Mode #6175
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
🦋 Changeset detectedLatest commit: 59b0b21 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR addresses issues with external authentication buttons in React Strict Mode by converting from a lazy query to a regular query with skip logic and implementing a ref-based guard to prevent double-processing of authentication callbacks.
Key Changes:
- Replaced
useAvailableExternalAuthenticationsLazyQuerywithuseAvailableExternalAuthenticationsQueryusing conditional skip logic - Added
useRefto prevent double-processing of external auth callbacks in React Strict Mode - Removed problematic cleanup logic from useEffect that was clearing localStorage during simulated unmounts
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| src/auth/views/Login.tsx | Converted lazy query to regular query with skip parameter; added ref-based guard for callback processing; removed cleanup logic from useEffect |
| src/auth/components/LoginPage/LoginPage.test.tsx | Improved test structure with helper function; added test cases for edge cases (empty array, undefined); removed mock in favor of actual MemoryRouter |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #6175 +/- ##
========================================
Coverage 39.56% 39.56%
========================================
Files 2415 2415
Lines 39920 39918 -2
Branches 8821 9149 +328
========================================
+ Hits 15794 15795 +1
+ Misses 24100 24097 -3
Partials 26 26 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
src/auth/views/Login.tsx
Outdated
| useEffect(() => { | ||
| const { code, state } = params; | ||
| const externalAuthParamsExist = code && state && isCallbackPath; | ||
| const externalAuthNotPerformed = !authenticating && !errors.length; | ||
|
|
||
| if (externalAuthParamsExist && externalAuthNotPerformed) { | ||
| handleExternalAuthentication(code, state); | ||
| // Guard against double-processing in React Strict Mode | ||
| if (isExternalAuthCallback && externalAuthNotPerformed && !externalAuthProcessedRef.current) { | ||
| externalAuthProcessedRef.current = true; | ||
| handleExternalAuthentication(code!, state!); | ||
| } | ||
|
|
||
| return () => { | ||
| setRequestedExternalPluginId(null); | ||
| setFallbackUri(null); | ||
| }; | ||
| }, []); | ||
| }, [isExternalAuthCallback, authenticating, errors.length]); |
Copilot
AI
Dec 4, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The useEffect hook is missing handleExternalAuthentication, code, and state in its dependency array. According to React's exhaustive-deps rule, all values used inside the effect that come from the component scope should be included in the dependency array.
Since handleExternalAuthentication is defined in the component, it should either be:
- Added to the dependency array along with
codeandstate(which would require memoizinghandleExternalAuthenticationwithuseCallback) - Or moved inside the
useEffectto avoid the dependency
The recommended fix is to move the function definition inside the useEffect:
useEffect(() => {
const externalAuthNotPerformed = !authenticating && !errors.length;
if (isExternalAuthCallback && externalAuthNotPerformed && !externalAuthProcessedRef.current) {
externalAuthProcessedRef.current = true;
const handleExternalAuthentication = async (code: string, state: string) => {
await loginByExternalPlugin!(requestedExternalPluginId, {
code,
state,
});
setRequestedExternalPluginId(null);
navigate(fallbackUri);
setFallbackUri(null);
};
handleExternalAuthentication(code!, state!);
}
}, [isExternalAuthCallback, authenticating, errors.length, loginByExternalPlugin, requestedExternalPluginId, setRequestedExternalPluginId, navigate, fallbackUri, setFallbackUri, code, state]);| // Track if external auth callback has been processed to avoid double-processing in Strict Mode | ||
| const externalAuthProcessedRef = useRef(false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue: I don't think we should create hacks to work around strict mode, if we have issue there it probably means we have something wrong with our implementation. It's worth checking ESLint warnings.
There's also a possibility we could introduce a bug here, as copilot wrote: https://github.com/saleor/saleor-dashboard/pull/6175/files#r2589250212
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As far as I see it it's not necessarily a hack for React Strict Mode per se. What should we do when component remounts and Apollo has the lazy query in flight?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Assuming we can't have that race condition realistically outside of strict mode the ref is indeed unnecessary but what do we do then for the strict mode so it works as expected?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment was I think already addressed.
| // Guard against double-processing in React Strict Mode | ||
| if (isExternalAuthCallback && externalAuthNotPerformed && !externalAuthProcessedRef.current) { | ||
| externalAuthProcessedRef.current = true; | ||
| handleExternalAuthentication(code!, state!); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue: again we probably have issue somewhere else, we shouldn't write specific fixes to Strict mode
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.
No description provided.