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

Dependent Suspense Queries #65

Open
kalijonn opened this issue Jan 22, 2024 · 7 comments
Open

Dependent Suspense Queries #65

kalijonn opened this issue Jan 22, 2024 · 7 comments

Comments

@kalijonn
Copy link
Collaborator

Currently dependent queries can be used only with atomWithQuery.

In the scenario of 2 atoms, we can get the result of the first atom by unwrap which resolves to be undefined/Result. We use the enabled flag on the 2nd atom to make the API request only when its 'Result'

We cannot await because these atoms don't support async getOptions.

@dai-shi
Copy link
Member

dai-shi commented Jan 22, 2024

Does #30 help? Or it's unrelated.

@wolfgang-cognify
Copy link

Same problem here, unfortunately :-/

@jaens
Copy link

jaens commented Feb 15, 2024

#30 would have helped, except it was removed in 0.8.0...

...so it's not possible to use Suspense and dependent queries at the same time at all now?

(I thought about atom-izing some of my queries but this seems to be a blocker since all the queries are designed around using Suspense.)

The next version of React will have a general use(Promise) hook, which would fix all these problems of mixing suspense vs. non-suspense APIs (by making the component itself be able to decide whether to suspend or not), so removing async support seems like a step backwards...

@grzesiek-ds
Copy link

In relation to this comment and this PR - I have a idea how to retrieve this feature.

My proposal involves abandoning the use of baseAtomWithQuery and separating the implementation of atomWithQuery and atomWithSuspenseQuery.

In my view, the main distinction between query hooks and atoms lies in the fact that hooks serve as a proxy for the queryObserver API, whereas atoms need to hold a value. This complexity becomes apparent when trying to achieve sometimes-async functionality.

Due to this difference, atoms cannot replicate the implementation of hooks, requiring a different approach.

I'd like to hear your opinion on this approach @kalijonn

@kalijonn
Copy link
Collaborator Author

In my view, the main distinction between query hooks and atoms lies in the fact that hooks serve as a proxy for the queryObserver API, whereas atoms need to hold a value. This complexity becomes apparent when trying to achieve sometimes-async functionality.

Interesting take. My mental model was that an atom is a proxy for the store. atom itself doesn't hold a value but a config that lets you get that value from the store. My mental model around a store was that it's an observable. In libraries like jotai-tanstack-query and jotai-urql, we are working with an additional observable. In the read function of the atoms, we also setup a subscription (to the additional observable - tanstack/urql).

I would love to know what @dai-shi thinks.

But I agree that it needs a different approach compared to hooks. With hooks, we are leveraging react to suspend when the 1st query is in flight which ensures the 2nd query is never triggered. And when 1st query is completed, 2nd query can access it's contents and the component still suspends until the 2nd query is resolved. The problem with our scenario is the dependency graph is outside react. While the component suspends while the 1st query is in flight, it doesn't stop the 2nd query from fetching.

This makes me want to try creating a Promise that doesn't resolve or reject until both are done synchronously. I've worked on this so long ago that I don't remember if I tried this already and found some issue.

@dai-shi
Copy link
Member

dai-shi commented Mar 15, 2024

Well, an atom has a value in a store, and we try best to synchronize it with the outside world. It's the same with hooks, hooks have values in a React fiber.

The problem with our scenario is the dependency graph is outside react.

I agree that it's the difference.

@grzesiek-ds
Copy link

grzesiek-ds commented Apr 2, 2024

Sorry, I took some mental shortcuts and it seem to be a cause of misunderstanding.

When using useQuery/useSuspenseQuery state is held in two places - query cache, and in react fibers.
When using atomWithQuery/atomWithSuspenseQuery state is held in three places - query cache, react fibers and in jotai store.

When component is getting unmounted, then query result is no longer kept as state of react fiber.
When component is getting mounted again (eg. after resetting error boundary) we can run some code (eg. reset query) before react fiber will establish it's state.

Therefore, if query result has an error, we can somehow modify query state, before agreeing what should be the state for react fiber.

With jotai it's getting more complicated, because if query atom has an error (mental shortcut there - as You have mentioned, atom is a proxy for fragment of store), we need to either manually set value for that atom, or somehow trigger recalculation of it.

I propose to cut this discussion out there, and move it to #75.

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

No branches or pull requests

5 participants