facebook / relay

Relay is a JavaScript framework for building data-driven React applications.
https://relay.dev
MIT License
18.4k stars 1.82k forks source link

Async Relay Resolvers #4537

Open alex-statsig opened 11 months ago

alex-statsig commented 11 months ago

There is no mention on Relay Resolvers about async resolvers / promises, and they seem to not work currently (I get an error about the object not having an "id" field, since the unresolved promise does not have the field; related #4536). I'm trying to use the experimental Relay Resolvers to nicely manage optimistic states / updaters and querying for several external REST APIs for a client-only app. To do this, async resolvers are necessary to make the REST calls. The Relay Resolvers system seems like a really cool way to support something like this, since I can just write clientside code to fetch data for a field and have relay manage syncing that across my app / fetching as needed if its not cached etc. The lack of async seems like a restrictive limitation atm. Is this something that is planned to be changed?

captbaritone commented 10 months ago

We are planing to land public documentation of resolvers in Dec/Jan but in the mean time, Live Resolvers can return a suspense sentinel to indicate that they are in a loading state. You can get the sentinel value from here: https://github.com/facebook/relay/blob/e854fa04acfef0421001d507b220a0c74f7f38b6/packages/relay-runtime/store/experimental-live-resolvers/LiveResolverSuspenseSentinel.js#L18

This should cause any component reading that field to suspend.

alex-statsig commented 10 months ago

We are planing to land public documentation of resolvers in Dec/Jan but in the mean time, Live Resolvers can return a suspense sentinel to indicate that they are in a loading state. You can get the sentinel value from here:

https://github.com/facebook/relay/blob/e854fa04acfef0421001d507b220a0c74f7f38b6/packages/relay-runtime/store/experimental-live-resolvers/LiveResolverSuspenseSentinel.js#L18

This should cause any component reading that field to suspend.

Gotcha, then I assume I would manually commit an update to the store once my promise resolves. Although I'm not sure how to get a reference to the store from there?

ex. something like this:

function myResolver() {
  fetchData()
    .then((result) => {
      store.commitLocalUpdate(..., result);
    })
    .catch((e) => store.commitLocalUpdate(..., null));
  return suspenseSentinel();
}

Thanks for the info about documentation timeline / "suspense sentinels", I was just eager to try this out on a personal project early!

ameyms commented 2 months ago

Hello folks! Wondering when suspenseSentinel (and also LiveState type) will be available via Relay and @types/relay-runtime. We are very interested in using these features here at Atlassian.

Some documentation would be amazing too! 🙏🏾

Thanks so much!!!

tobias-tengler commented 2 months ago

Documentation can be found here:

I'll try to raise a PR for the types later today :)

EDIT: Here's the PR https://github.com/DefinitelyTyped/DefinitelyTyped/pull/70229

tobias-tengler commented 2 months ago

@types/relay-runtime 17.0.4 now includes the types for LiveState<T> and suspenseSentinel.

ameyms commented 2 months ago

Thank you so much for the quick PR @tobias-tengler!!!! You literally unblocked me!!

ameyms commented 2 months ago

@captbaritone (sorry for the @ mention)

But... would it be possible to throw in a quick example/psuedocode here of how suspenseSentinel is to be used in conjunction with Promises (due to a server API call via fetch)