-
Notifications
You must be signed in to change notification settings - Fork 252
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
Upgraded to React 18, updated dependencies, fixed "AuthUI instance is deleted" error #173
base: master
Are you sure you want to change the base?
Conversation
…tWillMount/componentWillUnmount to solve React 18 strict mode issues
Hi, is it ready to be merged? |
When is it getting merged? |
@jhuleatt can you review and merge? |
Hi all. I need this PR merged right now. Thank you |
Hey when is this fix getting merged? |
@jhuleatt any feedback on the PR? Can we get this merged soon? |
waiting for merge |
waiting for merge +1 |
waiting for merge +2 |
I too would greatly appreciate this getting merged |
React solutionBased on this PR, if anyone is using React (create-react-app and not Next.js or other) and is looking for a way of solving this issue, you can get rid of
import { useEffect, useRef, useState } from 'react';
import { onAuthStateChanged } from 'firebase/auth';
import * as firebaseui from 'firebaseui';
import 'firebaseui/dist/firebaseui.css';
interface Props {
// The Firebase UI Web UI Config object.
// See: https://github.com/firebase/firebaseui-web#configuration
uiConfig: firebaseui.auth.Config;
// Callback that will be passed the FirebaseUi instance before it is
// started. This allows access to certain configuration options such as
// disableAutoSignIn().
uiCallback?(ui: firebaseui.auth.AuthUI): void;
// The Firebase App auth instance to use.
firebaseAuth: any; // As firebaseui-web
className?: string;
}
const StyledFirebaseAuth = ({uiConfig, firebaseAuth, className, uiCallback}: Props) => {
const [userSignedIn, setUserSignedIn] = useState(false);
const elementRef = useRef(null);
useEffect(() => {
// Get or Create a firebaseUI instance.
const firebaseUiWidget = firebaseui.auth.AuthUI.getInstance() || new firebaseui.auth.AuthUI(firebaseAuth);
if (uiConfig.signInFlow === 'popup')
firebaseUiWidget.reset();
// We track the auth state to reset firebaseUi if the user signs out.
const unregisterAuthObserver = onAuthStateChanged(firebaseAuth, (user) => {
if (!user && userSignedIn)
firebaseUiWidget.reset();
setUserSignedIn(!!user);
});
// Trigger the callback if any was set.
if (uiCallback)
uiCallback(firebaseUiWidget);
// Render the firebaseUi Widget.
// @ts-ignore
firebaseUiWidget.start(elementRef.current, uiConfig);
return () => {
unregisterAuthObserver();
firebaseUiWidget.reset();
};
}, [firebaseui, uiConfig]);
return <div className={className} ref={elementRef} />;
};
export default StyledFirebaseAuth; That's it! You can use this component without the need for this library. I just did this for my personal project and reduced the main bundle size by ~9KB. |
waiting for merge +3 |
me too! |
Please merge it :) |
merge 🙏 |
Pretty please with chocolate sprinkles on top? 🙏 |
Give me permission and I'll merge it. This project feels unmaintained. |
waiting for merge +999 |
Can this be merged? |
Please merge this; no reason not to. |
@jhuleatt and @Skyblueballykid , this merge is important for my team's project! Please be a kind soul and help us unblock. At least, by when should this PR get merged in? |
Next.js solutionFor anyone looking for a solution for
import { useEffect, useRef, useState } from 'react';
import { onAuthStateChanged } from 'firebase/auth';
import 'firebaseui/dist/firebaseui.css';
import {auth} from "firebaseui";
interface Props {
// The Firebase UI Web UI Config object.
// See: https://github.com/firebase/firebaseui-web#configuration
uiConfig: auth.Config;
// Callback that will be passed the FirebaseUi instance before it is
// started. This allows access to certain configuration options such as
// disableAutoSignIn().
uiCallback?(ui: auth.AuthUI): void;
// The Firebase App auth instance to use.
firebaseAuth: any; // As firebaseui-web
className?: string;
}
const StyledFirebaseAuth = ({uiConfig, firebaseAuth, className, uiCallback}: Props) => {
const [firebaseui, setFirebaseui] = useState<typeof import('firebaseui') | null>(null);
const [userSignedIn, setUserSignedIn] = useState(false);
const elementRef = useRef(null);
useEffect(() => {
// Firebase UI only works on the Client. So we're loading the package only after
// the component has mounted, so that this works when doing server-side rendering.
setFirebaseui(require('firebaseui'));
}, []);
useEffect(() => {
if (firebaseui === null )
return;
// Get or Create a firebaseUI instance.
const firebaseUiWidget = firebaseui.auth.AuthUI.getInstance() || new firebaseui.auth.AuthUI(firebaseAuth);
if (uiConfig.signInFlow === 'popup')
firebaseUiWidget.reset();
// We track the auth state to reset firebaseUi if the user signs out.
const unregisterAuthObserver = onAuthStateChanged(firebaseAuth, user => {
if (!user && userSignedIn)
firebaseUiWidget.reset();
setUserSignedIn(!!user);
});
// Trigger the callback if any was set.
if (uiCallback)
uiCallback(firebaseUiWidget);
// Render the firebaseUi Widget.
// @ts-ignore
firebaseUiWidget.start(elementRef.current, uiConfig);
return () => {
unregisterAuthObserver();
firebaseUiWidget.reset();
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [firebaseui, uiConfig]);
return <div className={className} ref={elementRef} />;
};
export default StyledFirebaseAuth; That's it! You can use this component without the need for this library. |
Waiting for merge 🙏 |
pls merge! |
Perfect and worked like a charm! Thanks. |
Hey guys come on! Many people are looking for this, it is as simple as merging it, just do it or give access to someone else that will actually maintain it. |
worked like a charm! Thank you 🤙 |
This is fantastic, but I found that redirects (e.g. with Google SSO or Email Link) still do not work correctly in development due to React.StrictMode and the new React 18 "strict effects" feature forcing an unmount and remount after firebaseUiWidget.start(...) transitions from temporary redirect link to the sign-in URL. Couldn't figure out a clean solution here, so went with a hack that skips unmount/remount when redirection is in play. const skipStrictEffects = useRef(false);
useEffect(() => {
...
if (!skipStrictEffects.current) {
skipStrictEffects.current = firebaseUiWidget.isPendingRedirect();
firebaseUiWidget.start(elementRef.current, uiConfig);
}
return () => {
if (!skipStrictEffects.current) {
unregisterAuthObserver();
firebaseUiWidget.reset();
}
};
}, [firebaseui, uiConfig]); |
can we get this merged please? |
@gvillenave Is this ready to be merged? |
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.
Let's merge <3
Could we merge this please @jhuleatt? |
I think this project is dead - 11 month since last update with many pleas to merge. I recommend removing the dependency as mentioned above. |
Since my project isn't using TSX and I had issues converting from TSX to JSX/JS, I ended up doing the following: yarn remove react-firebaseui
yarn add https://github.com/gvillenave/firebaseui-web-react.git#acb47b46dc39682d13f2b117524bda95ec1aeddf In my project, I am importing as follows: import StyledFirebaseAuth from 'react-firebaseui/dist/StyledFirebaseAuth'; Not ideal, I know 👎 |
It is a shame that this project is dead |
Have been looking into this for a bit and this seems to be by far the best fix atm. Turning off Strict Mode is very non-ideal, and I can confirm this works with the latest version of React while leaving it on. Works with Create-React-App (using Vite) as well. Thank you greatly! |
A note for anyone experiencing an error like the following when using these solutions:
import firebase from "firebase/compat/app";
import "firebase/compat/auth"; |
react 18 strict mode effects on useEffect is meant to tackle fast navigation or something like that. a better solution than above is to use event loop to run code that's affected by the unmount-remount, like so: useEffect(() => {
if (!elementRef.current) return;
let firebaseUiWidget: auth.AuthUI;
let unregisterAuthObserver: Unsubscribe;
// firebase ui start in event loop to solve react 18 strict requirement.
const timeout = setTimeout(() => {
// Get or Create a firebaseUI instance.
firebaseUiWidget =
auth.AuthUI.getInstance() || new auth.AuthUI(firebaseAuth);
if (uiConfig.signInFlow === "popup") firebaseUiWidget.reset();
// We track the auth state to reset firebaseUi if the user signs out.
unregisterAuthObserver = onAuthStateChanged(firebaseAuth, (user) => {
if (!user && userSignedIn) firebaseUiWidget.reset();
setUserSignedIn(!!user);
});
// Trigger the callback if any was set.
if (uiCallback) uiCallback(firebaseUiWidget);
// Render the firebaseUi Widget.
firebaseUiWidget.start(elementRef.current as HTMLDivElement, uiConfig);
});
return () => {
clearTimeout(timeout);
if (unregisterAuthObserver) unregisterAuthObserver();
if (firebaseUiWidget) firebaseUiWidget.reset();
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [uiConfig]); |
Thank you for nice library and nice PR. @jhuleatt |
componentWillMount
/componentWillUnmount
to auseEffect
hookuseRef
extract-text-webpack-plugin
(now deprecated) tomini-css-extract-plugin
andpostcss