* Move sample-simple to Concurrent Mode * Preload a query and lazy import Firestore * more work on async/preloading * demonstrate useTransition * Update docs * add note about experimental react build * Update rollup config Now that we're doing lazy imports with multiple chunks, rollup needs to output to a directory * docs fixes * lazy import the rest of the SDKs * remove some extra imports * remove some extra imports
5.8 KiB
Common Patterns
- Access your
firebaseobject from any component - Manage Loading States
- Access the current user
- Lazy Load the Firebase SDKs
- Preloading
Access your firebase object from any component
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');
// ...
}
Manage Loading States
Reactfire is designed to integrate with React's Suspense API, but also supports use cases where Suspense isn't needed or wanted.
Default: Suspense
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>
);
}
Bonus: SuspenseWithPerf
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>
);
}
Provide an initial value
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 />;
}
Access the current user
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.
Decide what to render based on a user's auth state
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>
);
Lazy Load the Firebase SDKs
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>;
}
Preloading
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
Preload an SDK
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.
Preload Data
Many ReactFire hooks have corresponding preload functions. For example, you can call preloadFirestoreDocData to preload data if a component later calls useFirestoreDocData.