diff --git a/react-providerx/src/observableProvider/autoDispose.ts b/react-providerx/src/observableProvider/autoDispose.ts index 3945bb7..9d9e7f9 100644 --- a/react-providerx/src/observableProvider/autoDispose.ts +++ b/react-providerx/src/observableProvider/autoDispose.ts @@ -2,11 +2,12 @@ import { BehaviorSubject, from, Observable, Subscription } from "rxjs"; export class AutoDisposeObservableProvider { behaviorSubject$: BehaviorSubject | BehaviorSubject - observableCreator: () => (Observable | null) - observable$?: (Observable | null) + observableCreator: () => Observable + _observable$: Observable - constructor(observableCreator: () => (Observable | null)) { + constructor(observableCreator: () => Observable) { this.observableCreator = observableCreator + this._observable$ = this.observableCreator() this.behaviorSubject$ = new BehaviorSubject(null) this._compute() } @@ -15,6 +16,10 @@ export class AutoDisposeObservableProvider { return this.behaviorSubject$.value } + get observable() { + return this._observable$ + } + static fromPromise(promise: () => Promise): AutoDisposeObservableProvider { return new AutoDisposeObservableProvider(() => (from(promise()) as any)) } @@ -26,24 +31,23 @@ export class AutoDisposeObservableProvider { } subscribe(subscribeCallback: (param: T) => void): Subscription { - if(this.observable$ === null || this.observable$ === undefined) { + if(this._observable$ === null || this._observable$ === undefined) { this._compute() } return (this.behaviorSubject$.asObservable() as any).subscribe(subscribeCallback) } _compute() { - this.observable$ = this.observableCreator() - if(this.observable$ === null) { + if(this._observable$ === null) { throw 'observableCreator cannot return null. It must return an instance of Observable' } - this.observable$.subscribe((val: T) => { + this._observable$.subscribe((val: T) => { this.behaviorSubject$.next(val as any) }) } _reset() { - this.observable$ = null + this._observable$ = this.observableCreator() this.behaviorSubject$ = new BehaviorSubject(null) } diff --git a/react-providerx/src/observableProvider/exporter.ts b/react-providerx/src/observableProvider/exporter.ts deleted file mode 100644 index e68a31c..0000000 --- a/react-providerx/src/observableProvider/exporter.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { AutoDisposeObservableProvider } from './autoDispose' -import { ObservableProvider } from './index' - -export { ObservableProvider, AutoDisposeObservableProvider } diff --git a/react-providerx/src/observableProvider/index.ts b/react-providerx/src/observableProvider/index.ts index 6586a6b..a506f1e 100644 --- a/react-providerx/src/observableProvider/index.ts +++ b/react-providerx/src/observableProvider/index.ts @@ -1,25 +1,30 @@ import { BehaviorSubject, from, Observable, Subscription } from 'rxjs' -import { AutoDisposeObservableProvider } from './exporter' +import { AutoDisposeObservableProvider } from './autoDispose' export class ObservableProvider { behaviorSubject$: BehaviorSubject | BehaviorSubject - observableCreator: () => (Observable | null) - observable$?: (Observable | null) + observableCreator: () => Observable + _observable$: Observable - constructor(observableCreator: () => (Observable | null)) { + constructor(observableCreator: () => Observable) { this.observableCreator = observableCreator + this._observable$ = this.observableCreator() this.behaviorSubject$ = new BehaviorSubject(null) this._compute() } - static autoDispose(observableCreator: () => (Observable | null)) { + static autoDispose(observableCreator: () => Observable) { return new AutoDisposeObservableProvider(observableCreator); } get value() { return this.behaviorSubject$.value } + + get observable() { + return this._observable$ + } static fromPromise(promise: () => Promise): ObservableProvider { return new ObservableProvider(() => (from(promise()) as any)) @@ -32,27 +37,27 @@ export class ObservableProvider { } subscribe(subscribeCallback: (param: T) => void): Subscription { - if(this.observable$ === null || this.observable$ === undefined) { + if(this._observable$ === null || this._observable$ === undefined) { this._compute() } return (this.behaviorSubject$.asObservable() as any).subscribe(subscribeCallback) } _compute() { - this.observable$ = this.observableCreator() - if(this.observable$ === null) { + if(this._observable$ === null) { throw 'observableCreator cannot return null. It must return an instance of Observable' } - this.observable$.subscribe((val: T) => { + this._observable$.subscribe((val: T) => { this.behaviorSubject$.next(val as any) }) } _reset() { - this.observable$ = null + this._observable$ = this.observableCreator() this.behaviorSubject$ = new BehaviorSubject(null) } registerUnsubscribe() { + } } diff --git a/tests/react-providerx-test-app/src/pages/HomePage/homePage.tsx b/tests/react-providerx-test-app/src/pages/HomePage/homePage.tsx index 7b85aff..a42e8bc 100644 --- a/tests/react-providerx-test-app/src/pages/HomePage/homePage.tsx +++ b/tests/react-providerx-test-app/src/pages/HomePage/homePage.tsx @@ -1,9 +1,23 @@ -import { useProvider } from "react-providerx"; +import { refresh, useProvider } from "react-providerx"; import { signOut } from "../../services/auth"; -import { authStateProvider$ } from "../../shared/authState"; +import { userDataPromiseProvider$ } from "../../shared/userData"; + +const SubComponent: React.FC = () => { + const { isLoading, data: userData } = useProvider(userDataPromiseProvider$) + if(isLoading) { + return
+ Loading... +
+ } + return ( +
+ {(userData as any).email} +
+ ); +} export const HomePage: React.FC = () => { - const { isLoading, data: user } = useProvider(authStateProvider$) + const { isLoading, data: userData } = useProvider(userDataPromiseProvider$) if(isLoading) { return
Loading... @@ -11,10 +25,16 @@ export const HomePage: React.FC = () => { } return (
- {(user as any).displayName} - + {(userData as any).email} +
+ + +
+
); } diff --git a/tests/react-providerx-test-app/src/services/auth.ts b/tests/react-providerx-test-app/src/services/auth.ts index d3d47bf..dd0e962 100644 --- a/tests/react-providerx-test-app/src/services/auth.ts +++ b/tests/react-providerx-test-app/src/services/auth.ts @@ -1,8 +1,21 @@ -import { auth, googleAuthProvider } from "../utils/firebase" +import { auth, db, googleAuthProvider } from "../utils/firebase" export const signInWithGoogle = async () => { const credential = await auth.signInWithPopup(googleAuthProvider) - return credential.user + const user = credential.user + if(user === null) { + return null + } + const userDocSnapshot = await db.collection('users').doc(user.uid).get() + if(!userDocSnapshot.exists) { + await db.collection('users').doc(user.uid).set({ + uid: user.uid, + email: user.email, + displayName: user.displayName, + photoURL: user.photoURL, + }) + } + return user } export const signOut = async () => { diff --git a/tests/react-providerx-test-app/src/shared/authState.ts b/tests/react-providerx-test-app/src/shared/authState.ts index 4827d0c..a95a241 100644 --- a/tests/react-providerx-test-app/src/shared/authState.ts +++ b/tests/react-providerx-test-app/src/shared/authState.ts @@ -1,14 +1,10 @@ import { ObservableProvider } from "react-providerx"; import { authState } from 'rxfire/auth' -import { map, tap } from 'rxjs/operators' +import { map } from 'rxjs/operators' import { auth } from "../utils/firebase"; export const authStateProvider$ = new ObservableProvider(() => { return authState(auth).pipe( - map(u => u === null ? 'not-logged-in': u), - tap(result => { - console.log('the value of result is') - console.log(result) - }) + map(u => u === null ? 'not-logged-in': u) ) }) diff --git a/tests/react-providerx-test-app/src/shared/userData.ts b/tests/react-providerx-test-app/src/shared/userData.ts new file mode 100644 index 0000000..ae9a8b3 --- /dev/null +++ b/tests/react-providerx-test-app/src/shared/userData.ts @@ -0,0 +1,26 @@ +import { ObservableProvider } from "react-providerx"; +import { of } from "rxjs"; +import { doc } from 'rxfire/firestore'; +import { map, switchMap, tap } from "rxjs/operators"; +import { db } from "../utils/firebase"; +import { authStateProvider$ } from "./authState"; + +export const userDataPromiseProvider$ = new ObservableProvider(() => { + const userDataObservable = authStateProvider$.observable.pipe( + switchMap(result => { + if(result === null || result === 'not-logged-in') { + return of(null) + } + else { + return doc(db.doc(`users/${result.uid}`)).pipe( + map(ds => ds.data()), + tap(userData => { + console.log('Got userData: ') + console.log(userData) + }) + ) + } + }) + ) + return userDataObservable +})