-
Notifications
You must be signed in to change notification settings - Fork 410
/
Copy pathfirebaseApp.tsx
85 lines (67 loc) · 2.85 KB
/
firebaseApp.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
import * as React from 'react';
import { getApps, initializeApp, registerVersion } from 'firebase/app';
import type { FirebaseApp, FirebaseOptions } from 'firebase/app';
// INVESTIGATE I don't like magic strings, can we have export this in js-sdk?
const DEFAULT_APP_NAME = '[DEFAULT]';
const FirebaseAppContext = React.createContext<FirebaseApp | undefined>(undefined);
const SuspenseEnabledContext = React.createContext<boolean>(false);
export interface FirebaseAppProviderProps {
firebaseApp?: FirebaseApp;
firebaseConfig?: FirebaseOptions;
appName?: string;
suspense?: boolean;
}
// REACTFIRE_VERSION is automatically pulled in from `package.json` by Vite
export const version = process.env.REACTFIRE_VERSION as string;
const shallowEq = (a: { [key: string]: any }, b: { [key: string]: any }) => a === b || [...Object.keys(a), ...Object.keys(b)].every((key) => a[key] === b[key]);
export function FirebaseAppProvider(props: React.PropsWithChildren<FirebaseAppProviderProps>) {
const { firebaseConfig, appName, suspense } = props;
const firebaseApp: FirebaseApp = React.useMemo(() => {
if (props.firebaseApp) {
return props.firebaseApp;
}
const existingApp = getApps().find((app) => app.name === (appName || DEFAULT_APP_NAME));
if (existingApp) {
if (firebaseConfig && shallowEq(existingApp.options, firebaseConfig)) {
return existingApp;
} else {
throw new Error(
`Does not match the options already provided to the ${appName || 'default'} firebase app instance, give this new instance a different appName.`
);
}
} else {
if (!firebaseConfig) {
throw new Error('No firebaseConfig provided');
}
const reactVersion = React.version || 'unknown';
registerVersion('react', reactVersion);
registerVersion('reactfire', version);
return initializeApp(firebaseConfig, appName);
}
}, [props.firebaseApp, firebaseConfig, appName]);
return (
<FirebaseAppContext.Provider value={firebaseApp}>
<SuspenseEnabledContext.Provider value={suspense ?? false} {...props} />
</FirebaseAppContext.Provider>
);
}
export function useIsSuspenseEnabled(): boolean {
const suspense = React.useContext(SuspenseEnabledContext);
// default to false if not available in context
return suspense ?? false;
}
export function useSuspenseEnabledFromConfigAndContext(suspenseFromConfig?: boolean): boolean {
const suspenseFromContext = React.useContext(SuspenseEnabledContext);
// prioritize config over context
if (suspenseFromConfig !== undefined) {
return suspenseFromConfig;
}
return suspenseFromContext;
}
export function useFirebaseApp() {
const firebaseApp = React.useContext(FirebaseAppContext);
if (!firebaseApp) {
throw new Error('Cannot call useFirebaseApp unless your component is within a FirebaseAppProvider');
}
return firebaseApp;
}