Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(rxjs): Convert atomWithObservable to Observable spec #593

Merged
merged 1 commit into from
Jul 16, 2021
Merged

feat(rxjs): Convert atomWithObservable to Observable spec #593

merged 1 commit into from
Jul 16, 2021

Conversation

kitten
Copy link
Contributor

@kitten kitten commented Jul 15, 2021

This is a draft / WIP.

Ref: #234

This converts jotai/rxjs over to a generic atomWithObservable that potentially supports all Observable libraries that adhere to the Observable proposal.

To replace first the initial subscription unsubscribes at the earliest possible time, which takes synchronous (non-deferred) results into account. The resultAtom.onMount function will also now reuse the subscription if possible and otherwise start a new subscription, to match the previous implementation closely in its double-subscription behaviour.

@vercel
Copy link

vercel bot commented Jul 15, 2021

This pull request is being automatically deployed with Vercel (learn more).
To see the status of your deployment, click below or on the icon next to each commit.

🔍 Inspect: https://vercel.com/pmndrs/jotai/EVJw56QvTA2vdhcesnZKRicXHbhY
✅ Preview: https://jotai-git-fork-kitten-feat-rxjs-observable-spec-pmndrs.vercel.app

@codesandbox-ci
Copy link

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit 938c147:

Sandbox Source
React Configuration
React Typescript Configuration

Copy link
Member

@dai-shi dai-shi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well, seems like you already have a good understanding of jotai. supporting suspense has been tricky as you know.

import { atom } from 'jotai'
import type { Atom, WritableAtom, Getter } from 'jotai'

const observableSymbol: typeof Symbol.observable =
typeof Symbol === 'function'
Copy link
Member

@dai-shi dai-shi Jul 15, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Symbols are used everywhere, so we wouldn't need to support non-Symbol env specific here.

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'))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it'd be better to use Symbol.for() for the fallback? Or, is this the de-facto for the fallback?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After looking at the code, it's basically used only in L46-L47.
So, this could just be:

const observableSymbol = Symbol.observable || undefined

(meaning we don't need this)

Or, is there any specific reason we want to assign Symbol.observable with a unique symbol?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's an attempt to polyfill the Symbol.observable: https://github.com/benlesh/symbol-observable/blob/master/es/ponyfill.js

I'm not sure if it's the correct implementation.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. In such a case, const observableSymbol = Symbol.observable should be fine for us, and if really required, people should polyfill (not ponyfill) the symbol in their app code.

Comment on lines +75 to +81
subscription = observable.subscribe((data) => {
dataListener(data)
if (subscription && !setResult) {
subscription.unsubscribe()
subscription = null
}
}, errorListener)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this work like first()? We would need to unsubscribe on error too.

Comment on lines +82 to +85
if (!resolve) {
subscription.unsubscribe()
subscription = null
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the reason this would be required is subscription callback is invoked in sync, but then it's already unsubscribed.
hm, what's the intention behind this?

@dai-shi
Copy link
Member

dai-shi commented Jul 16, 2021

This converts jotai/rxjs over to a generic atomWithObservable that potentially supports all Observable libraries that adhere to the Observable proposal.

I like the idea very much! If this works, atomWithObservable should be in jotai/utils and we remove jotai/rxjs...

To replace first the initial subscription unsubscribes at the earliest possible time, which takes synchronous (non-deferred) results into account. The resultAtom.onMount function will also now reuse the subscription if possible and otherwise start a new subscription, to match the previous implementation closely in its double-subscription behaviour.

Sounds good. I assume you are expert on this topic.

@kitten
Copy link
Contributor Author

kitten commented Jul 16, 2021

Haha, I wouldn't call myself an expert, but I believe this would work with most Observable livraries and implementations. I'd still say though that there may be some that will cause edge cases, but that remains to be seen.

@dai-shi
Copy link
Member

dai-shi commented Jul 16, 2021

I'd still say though that there may be some that will cause edge cases, but that remains to be seen.

Yeah, probably. That said, if you are fine, I'd like to merge this and continue some tweaks on my end.

@dai-shi
Copy link
Member

dai-shi commented Jul 16, 2021

Or, I can work on this branch, if you prefer.

@kitten
Copy link
Contributor Author

kitten commented Jul 16, 2021

@dai-shi either works for me ✌️ I think I'll have to test some trampoline scheduled stuff to make sure first(1) is not going to be insufficiently replaced, but I'll do that in parallel

@dai-shi dai-shi marked this pull request as ready for review July 16, 2021 13:08
Copy link
Member

@dai-shi dai-shi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me merge this and create a new PR for some adjustments.

@dai-shi dai-shi merged commit 72447e7 into pmndrs:master Jul 16, 2021
@kitten kitten deleted the feat/rxjs-observable-spec branch July 16, 2021 13:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants