- Access your
firebase
object from any component - Manage Loading States
- Access the current user
- Lazy Load the Firebase SDKs
- Preloading
Since reactfire uses React's Context API, any component under a FirebaseAppProvider
can use useFirebaseApp()
to get your initialized app.
// ** INDEX.JS **
const firebaseConfig = {
/* add your config object from the Firebase console */
};
render(
<FirebaseAppProvider firebaseConfig={firebaseConfig}>
<MyApp />
</FirebaseAppProvider>
);
// ** MYCOMPONENT.JS **
function MyComponent(props) {
const firestore = useFirestore();
const documentReference = firestore()
.collection('burritos')
.doc('vegetarian');
// ...
}
Reactfire is designed to integrate with React's Suspense API, but also supports use cases where Suspense isn't needed or wanted.
Say we have a component called Burrito
that uses useFirestoreDoc
:
function Burrito() {
const firebaseApp = useFirestore();
const burritoRef = firestore()
.collection('tryreactfire')
.doc('burrito');
// subscribe to the doc. just one line!
// throws a Promise for Suspense to catch,
// and then streams live updates
const burritoDoc = useFirestoreDoc(burritoRef);
const isYummy = burritoDoc.data().yummy;
return <p>The burrito is {isYummy ? 'good' : 'bad'}!</p>;
}
The parent component of Burrito
can use Suspense
to render a fallback
component until useFirestoreDoc
returns a value:
function FoodRatings() {
return (
<Suspense fallback={'loading burrito status...'}>
<Burrito />
</Suspense>
);
}
Reactfire provides an a wrapper around Suspense
called SuspenseWithPerf
that instruments your Suspense
loads with a Firebase Performance Monitoring custom trace. It looks like this:
function FoodRatings() {
return (
<SuspenseWithPerf
fallback={'loading burrito status...'}
traceId={'load-burrito-status'}
>
<Burrito />
</SuspenseWithPerf>
);
}
What if we don't want to use Suspense, or we're server rendering and we know what the initial value should be? In that case we can provide an initial value to any Reactfire hook:
function Burrito() {
const firebaseApp = useFirebaseApp();
const burritoRef = firebaseApp
.firestore()
.collection('tryreactfire')
.doc('burrito');
// subscribe to the doc. just one line!
// returns the `startWithValue`,
// and then streams live updates
const burritoDoc = useFirestoreDocData(burritoRef, {
startWithValue: {
yummy: true
}
});
const isYummy = burritoDoc.data().yummy;
return <p>The burrito is {isYummy ? 'good' : 'bad'}!</p>;
}
The parent component of Burrito
now doesn't need to use Suspense
:
function FoodRatings() {
return <Burrito />;
}
The useUser()
hook returns the currently signed-in user. Like the other Reactfire Hooks, you need to wrap it in Suspense
or provide a startWithValue
.
function HomePage(props) {
// no need to use useFirebaseApp - useUser calls it under the hood
const user = useUser();
return <h1>Welcome Back {user.displayName}!</h1>;
}
Note: useUser
will also automatically lazily import the firebase/auth
SDK if it has not been imported already.
The AuthCheck
component makes it easy to hide/show UI elements based on a user's auth state. It will render its children if a user is signed in, but if they are not signed in, it renders its fallback
prop:
render(
<AuthCheck fallback={<LoginPage />}>
<HomePage />
</AuthCheck>
);
Including the Firebase SDKs in your main JS bundle (by using import 'firebase/firestore'
, for example) will increase your bundle size. To get around this, you can lazy load the Firebase SDK with ReactFire. As long as a component has a parent that is a FirebaseAppProvider
, you can use an SDK hook (useFirestore
, useDatabase
, useAuth
, useStorage
) like so:
MyComponent.jsx
import React from 'react';
// WE ARE NOT IMPORTING THE FIRESTORE SDK UP HERE
import { useFirestoreDocData, useFirestore } from 'reactfire';
export function MyComponent(props) {
// automatically lazy loads the Cloud Firestore SDK
const firestore = useFirestore();
const ref = firestore().doc('count/counter');
const data = useFirestoreDocData(ref);
return <h1>{data.value}</h1>;
}
The render-as-you-fetch pattern encourages kicking off requests as early as possible instead of waiting until a component renders. ReactFire supports this behavior
Just as the SDK hooks like useFirestore
can automatically fetch an SDK, you can call preloadFirestore
(or preloadAuth
, etc) to start loading an SDK without suspending.
Many ReactFire hooks have corresponding preload functions. For example, you can call preloadFirestoreDocData
to preload data if a component later calls useFirestoreDocData
.