Firebase React Context setup

React context

1
import React from 'react';
2
import ReactDOM from 'react-dom';
3
import './index.css';
4
import App from './App';
5
import * as serviceWorker from './serviceWorker';
6
import Firebase, { FirebaseContext } from './Components/Firebase';
7
​
8
ReactDOM.render(
9
<FirebaseContext.Provider value={ new Firebase() }>
10
<App />
11
</FirebaseContext.Provider>,
12
document.getElementById('root')
13
);
14
​
15
// If you want your app to work offline and load faster, you can change
16
// unregister() to register() below. Note this comes with some pitfalls.
17
// Learn more about service workers: http://bit.ly/CRA-PWA
18
serviceWorker.unregister();
Copied!

Firebase class

1
import app from 'firebase/app';
2
import 'firebase/auth';
3
import 'firebase/firestore';
4
​
5
const config = {
6
apiKey: process.env.REACT_APP_API_KEY,
7
authDomain: process.env.REACT_APP_AUTH_DOMAIN,
8
databaseURL: process.env.REACT_APP_DATABASE_URL,
9
projectId: process.env.REACT_APP_PROJECT_ID,
10
storageBucket: process.env.REACT_APP_STORAGE_BUCKET,
11
messagingSenderId: process.env.REACT_APP_MESSAGING_SENDER_ID
12
};
13
class Firebase {
14
constructor() {
15
app.initializeApp(config);
16
this.auth = app.auth();
17
this.db = app.firestore();
18
}
19
​
20
userRef = uid => this.db.doc(`users/${ uid }`);
21
usersRef = () => this.db.collection('users');
22
​
23
user = async uid => await this.userRef(uid).get();
24
users = async () => await this.usersRef().get();
25
// *** Merge Auth and DB User API *** //
26
​
27
onAuthUserListener = (next, fallback) =>
28
this.auth.onAuthStateChanged(async authUser => {
29
if (authUser) {
30
const dbSnapshot = await this.user(authUser.uid);
31
const dbUser = dbSnapshot.data();
32
​
33
// default empty roles
34
if (!dbUser.roles) {
35
dbUser.roles = {};
36
}
37
​
38
// merge auth and db user
39
const mergeUser = {
40
uid: authUser.uid,
41
email: authUser.email,
42
emailVerified: authUser.emailVerified,
43
providerData: authUser.providerData,
44
...dbUser
45
};
46
​
47
next(mergeUser);
48
} else {
49
fallback();
50
}
51
});
52
​
53
// doCreateUserWithEmailAndPassword = (email, password) =>
54
// this.auth.createUserWithEmailAndPassword(email, password);
55
doSignInWithEmailAndPassword = (email, password) =>
56
this.auth.signInWithEmailAndPassword(email, password);
57
doSignOut = () => this.auth.signOut();
58
doPasswordReset = email => this.auth.sendPasswordResetEmail(email);
59
doPasswordUpdate = password => this.auth.currentUser.updatePassword(password);
60
}
61
​
62
export default Firebase;
Copied!
digital-paper-edit-client/index.js at firebase Β· bbc/digital-paper-edit-client
GitHub
d
1
import FirebaseContext, { withFirebase } from './context';
2
import Firebase from './firebase';
3
​
4
export default Firebase;
5
​
6
export { FirebaseContext, withFirebase };
Copied!

Higher order component - consumer

1
import React from 'react';
2
​
3
const FirebaseContext = React.createContext(null);
4
​
5
export const withFirebase = Component => props => (
6
<FirebaseContext.Consumer>
7
{firebase => <Component { ...props } firebase={ firebase } />}
8
</FirebaseContext.Consumer>
9
);
10
export default FirebaseContext;
Copied!

Example usage

eg in a sign in page
1
import React, { useState } from 'react';
2
import { withRouter } from 'react-router-dom';
3
import { compose } from 'recompose';
4
import { withFirebase } from '../Firebase';
5
import * as ROUTES from '../../constants/routes';
6
const SignInPage = () => (
7
<div>
8
<h1>SignIn</h1>
9
<SignInForm />
10
</div>
11
);
12
​
13
const SignInFormBase = props => {
14
const [ email, setEmail ] = useState('');
15
const [ password, setPassword ] = useState('');
16
const [ error, setError ] = useState();
17
​
18
// TODO: IF signed in, forward always to somewhere else
19
const onSubmit = async event => {
20
try {
21
await props.firebase.doSignInWithEmailAndPassword(email, password);
22
setEmail('');
23
setPassword('');
24
setError(null);
25
props.history.push(ROUTES.PROJECTS);
26
} catch (err) {
27
setError(err);
28
}
29
event.preventDefault();
30
};
31
​
32
const onChange = event => {
33
console.log(event.target);
34
if (event.target.name === 'password') {
35
setPassword(event.target.value);
36
} else {
37
setEmail(event.target.value);
38
}
39
};
40
​
41
const isInvalid = password === '' || email === '';
42
​
43
return (
44
<form onSubmit={ onSubmit }>
45
<input
46
name="email"
47
value={ email }
48
onChange={ onChange }
49
type="text"
50
placeholder="Email Address"
51
/>
52
<input
53
name="password"
54
value={ password }
55
onChange={ onChange }
56
type="password"
57
placeholder="Password"
58
/>
59
<button disabled={ isInvalid } type="submit">
60
Sign In
61
</button>
62
​
63
{error && <p>{error.message}</p>}
64
</form>
65
);
66
};
67
​
68
const SignInForm = compose(withRouter, withFirebase)(SignInFormBase);
69
​
70
export default SignInPage;
71
​
72
export { SignInForm };
Copied!