はじめに
前回の記事では、react-firebase-hooksを試したのですが、12月6日のReact Day Berlinでは、ReactFireのプレゼンがありました。こちらはとても先進的で期待できます。
本記事では、Authの部分を移植してみたいと思います。
ReactFireとは
ReactFire v1は2016年5月のリリースを最後に、その後deprecateされ、Firebase JS SDKを直接使うようアナウンスされています。それが2019年7月よりv2として再度開発しているようです。
https://github.com/FirebaseExtended/reactfire
現在、masterブランチがv2になっています。
コーディング
import React, { Suspense, useState, useRef, useEffect } from "react";
import ReactDOM from "react-dom";
import "firebase/auth";
import { FirebaseAppProvider, useAuth, useUser } from "reactfire";
const firebaseConfig = {
apiKey: "...",
authDomain: "...",
databaseURL: "...",
projectId: "...",
storageBucket: "...",
messagingSenderId: "...",
appId: "..."
};
const Login = () => {
const auth = useAuth();
const [email, setEmail] = useState("");
const [pass, setPass] = useState("");
const [error, setError] = useState(null);
const [pending, setPending] = useState(false);
const mounted = useRef(true);
useEffect(() => {
const cleanup = () => {
mounted.current = false;
};
return cleanup;
}, []);
const onSubmit = async e => {
e.preventDefault();
setError(null);
setPending(true);
try {
await auth().signInWithEmailAndPassword(email, pass);
} catch (e) {
console.log(e.message, mounted);
if (mounted.current) setError(e);
} finally {
if (mounted.current) setPending(false);
}
};
return (
<div>
<form onSubmit={onSubmit}>
<input
type="email"
value={email}
onChange={e => setEmail(e.target.value)}
placeholder="Email..."
/>
<input
type="password"
value={pass}
onChange={e => setPass(e.target.value)}
placeholder="Password..."
/>
<button type="submit">Login</button>
{pending && "Pending..."}
{error && `Error: ${error.message}`}
</form>
</div>
);
};
const Logout = () => {
const auth = useAuth();
const [pending, setPending] = useState(false);
const mounted = useRef(true);
useEffect(() => {
const cleanup = () => {
mounted.current = false;
};
return cleanup;
}, []);
const logout = async () => {
setPending(true);
await auth().signOut();
if (mounted.current) setPending(false);
};
return (
<div>
<button type="button" onClick={logout}>
Logout
</button>
{pending && "Pending..."}
</div>
);
};
const Main = () => {
const user = useUser();
if (!user) {
return <Login />;
}
return (
<div>
User: {user.email}
<Logout />
</div>
);
};
const App = () => {
return (
<FirebaseAppProvider firebaseConfig={firebaseConfig}>
<Suspense fallback={<div>Loading...</div>}>
<Main />
</Suspense>
</FirebaseAppProvider>
);
};
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
動きました。nextではだめで、canaryを使う必要がありました。
おわりに
結果的には、前回のコードとそれほど変わっていないのですが、useUser
があるので、自分でcontextを用意しなくていい分は楽になるかもしれません。Suspenseでローディング処理を書かなくていいのも楽ではあります。