Skip to content

Commit

Permalink
feat(rxjs): Convert atomWithObservable to Observable spec
Browse files Browse the repository at this point in the history
  • Loading branch information
kitten committed Jul 15, 2021
1 parent e8eab67 commit 938c147
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 16 deletions.
12 changes: 6 additions & 6 deletions .size-snapshot.json
Original file line number Diff line number Diff line change
Expand Up @@ -154,16 +154,16 @@
}
},
"rxjs.js": {
"bundled": 1714,
"minified": 748,
"gzipped": 399,
"bundled": 2116,
"minified": 912,
"gzipped": 447,
"treeshaked": {
"rollup": {
"code": 37,
"import_statements": 37
"code": 103,
"import_statements": 14
},
"webpack": {
"code": 1054
"code": 1087
}
}
}
Expand Down
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,6 @@
"optics-ts": "*",
"react": ">=16.8",
"react-query": "*",
"rxjs": "*",
"valtio": "*",
"wonka": "*",
"xstate": "*"
Expand Down
58 changes: 49 additions & 9 deletions src/rxjs/atomWithObservable.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,51 @@
import { Observable, Subject } from 'rxjs'
import { first } from 'rxjs/operators'
import { atom } from 'jotai'
import type { Atom, WritableAtom, Getter } from 'jotai'

const observableSymbol: typeof Symbol.observable =
typeof Symbol === 'function'
? Symbol.observable || ((Symbol as any).observable = Symbol('observable'))
: ('@@observable' as any)

export interface Subscription {
unsubscribe(): void
}

export interface Observer<T> {
next(value: T): void
error(error: any): void
complete(): void
}

export interface ObservableLike<T> {
subscribe(observer: Observer<T>): Subscription
subscribe(
next: (value: T) => void,
error?: (error: any) => void,
complete?: () => void
): Subscription
[Symbol.observable]?(): ObservableLike<T>
}

export type SubjectLike<T> = ObservableLike<T> & Observer<T>

export function atomWithObservable<TData>(
createObservable: (get: Getter) => Subject<TData>
createObservable: (get: Getter) => ObservableLike<TData>
): WritableAtom<TData, TData>

export function atomWithObservable<TData>(
createObservable: (get: Getter) => Observable<TData>
createObservable: (get: Getter) => SubjectLike<TData>
): Atom<TData>

export function atomWithObservable<TData>(
createObservable: (get: Getter) => Observable<TData> | Subject<TData>
createObservable: (get: Getter) => ObservableLike<TData> | SubjectLike<TData>
) {
type Result = { data: TData } | { error: unknown }
const observableResultAtom = atom((get) => {
const observable = createObservable(get)
let resolve: ((result: Result) => void) | null = null
let observable = createObservable(get)
if (observable[observableSymbol]) {
observable = observable[observableSymbol]!()
}
const resultAtom = atom<Result | Promise<Result>>(
new Promise<Result>((r) => {
resolve = r
Expand All @@ -43,11 +71,23 @@ export function atomWithObservable<TData>(
setResult({ error })
}
}
observable.pipe(first()).toPromise().then(dataListener).catch(errorListener)
let subscription: Subscription | null = null
subscription = observable.subscribe((data) => {
dataListener(data)
if (subscription && !setResult) {
subscription.unsubscribe()
subscription = null
}
}, errorListener)
if (!resolve) {
subscription.unsubscribe()
subscription = null
}
resultAtom.onMount = (update) => {
setResult = update
const subscription = observable.subscribe(dataListener, errorListener)
return () => subscription.unsubscribe()
if (!subscription)
subscription = observable.subscribe(dataListener, errorListener)
return () => subscription && subscription.unsubscribe()
}
return { resultAtom, observable }
})
Expand Down

0 comments on commit 938c147

Please sign in to comment.