igorkamyshev / farfetched

The advanced data fetching tool for web applications
https://ff.effector.dev
MIT License
186 stars 34 forks source link

Query Chain #38

Open igorkamyshev opened 2 years ago

igorkamyshev commented 2 years ago

I've though about a lot about APIs for compatibility with chainRoute from Atomic Router. It's some conclusions 👇

Query is useless as a chainRoute source

Farfetched build around the idea of queries connection, it assumes that to load all information of a page it will be necessary to execute plenty of queries. So, simple chainRoute({ route, ...query.compatibleProtocol }) works only for single query, which is impossible in the real application.

Query as Effect note

It means, cast Query to Effect has no sense to make Farfecthed compatible with Atomic Router.

cc @sergeysova

Query Chain

As I discovered, single query has no sense as source of chainQuery (or other method to postpone routing until data fetching). So, we need to subscribe router on the whole chain of queries. It means, data fetching with first queries should be started after some start event, and some all-done-event should be fired after all queries successfully loads.

For example 👇

const profileQuery = createQuery()
const settingsQuery = createQuery()
const privacyQuery = createQuery()

connectQuery({ source: profileQuery, target: [settingsQuery, privacyQuery] })

In this application, profile page should be opened only after all three queries successfully done. It can be represented with something like this:

// It is not API proposal, just example

const profileLoadedRoute = chainRoute({
  route: profileRoute,
  beforeOpen: {
    effect: queryChain({ startAt: profileQuery }),
  },
});

In this case, queryChain could return Effect. Start of the Effect will start the first Query in the chain, .done-event will represent successfully load of profileQuery, settingsQuery and privacyQuery.

Further steps

We have to collect some real-world feedback and feedback from Effector Committee before implementing this proposal.

Drevoed commented 2 years ago

Seems like a pretty neat idea. But why is there a need for a dedicated operator? This seems like something a simple wrapper around allSettled would resolve.

const postLoadedRoute = chainRoute({
  route: postRoute,
  beforeOpen: {
    effect: createEffect(async () => await allSettled(profileQuery.start)),
  },
});
zerobias commented 2 years ago

Looks like we need allSettled without scopes in effector itself

igorkamyshev commented 2 years ago

I truly agree that allSettled without scope would be great 👍

However, I have to mention that allSettled cannot solve all cases of chained queries.

For example, in some cases, we can open a page after some essential queries and load other data after navigation. In can be solved by some parameters of queryChain, but plain allSettled cannot solve this case. So, in my mind, allSettled definitely would be pretty useful as a part internal implementation of queryChain.

zerobias commented 2 years ago

It is noteworthy that only queries are tracked, that is, there is no implicit transparency. This loosens things up a bit, giving you the certainty you need in the complex concept of transitioning through routes. "This is a query and it will lengthen the wait, this is just a connected effect with analytics and it will work in the background."