Created
May 10, 2023 02:05
-
-
Save omochi/7e0963918e191d5e8023b9b9ce8e527f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Auth } from "@firebase/auth"; | |
import * as firebaseui from "firebaseui"; | |
import { ReactElement, useEffect, useRef, useState } from "react"; | |
import { Random } from "../../components/Random"; | |
import { Box, BoxProps } from "@chakra-ui/react"; | |
export type FirebaseAuthViewProps = { | |
auth: Auth; | |
config: firebaseui.auth.Config; | |
} & BoxProps; | |
class FirebaseAuthViewImpl { | |
/* | |
UIの削除が非同期なので、 | |
マウントされている、かつ、削除中ではない時に、開始する。 | |
削除はアンマウントから起動するが、 | |
既に削除中であれば何もしない。 | |
*/ | |
auth: Auth; | |
ui: firebaseui.auth.AuthUI | null; | |
config: firebaseui.auth.Config; | |
elementID: string; | |
// マウントされている | |
isMounted: boolean; | |
// startを呼び出して、deleteを呼び出す前 | |
isStarted: boolean; | |
// delete呼び出して実行中 | |
deleteTask: Promise<void> | null; | |
constructor(auth: Auth, config: firebaseui.auth.Config, elementID: string) { | |
this.auth = auth; | |
this.ui = null; | |
this.config = config; | |
this.elementID = elementID; | |
this.isMounted = true; | |
this.isStarted = false; | |
this.deleteTask = null; | |
} | |
private start() { | |
if (this.ui == null) { | |
this.ui = new firebaseui.auth.AuthUI(this.auth); | |
} | |
this.ui!.start("#" + this.elementID, this.config); | |
this.isStarted = true; | |
} | |
private delete() { | |
this.isStarted = false; | |
this.deleteTask = this.ui!.delete().then(() => { | |
this.deleteTask = null; | |
this.ui = null; | |
this.mayStart(); | |
}); | |
} | |
private mayStart() { | |
if (this.isMounted && this.deleteTask == null) { | |
this.start(); | |
} | |
} | |
onMount() { | |
this.isMounted = true; | |
this.mayStart(); | |
} | |
onUnmount() { | |
if (this.isStarted && this.deleteTask == null) { | |
this.delete(); | |
} | |
this.isMounted = false; | |
} | |
} | |
export function FirebaseAuthView(props: FirebaseAuthViewProps): ReactElement { | |
const { | |
auth, | |
config, | |
...rest | |
} = props; | |
const [id, setID] = useState<string>(() => `auth-${ Random.htmlID() }`); | |
const implRef = useRef<FirebaseAuthViewImpl | null>(null); | |
useEffect(() => { | |
if (implRef.current == null) { | |
implRef.current = new FirebaseAuthViewImpl(auth, config, id); | |
} | |
implRef.current!.onMount(); | |
return () => { | |
implRef.current!.onUnmount(); | |
} | |
}, []); | |
return <Box id={ id } {...rest}></Box> | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
公式のやつが高速なmount/unmountで正しく動かないため、
React.StrictMode
で利用できなかったので、自作した。結局不要になったのでgistに供養する。