timhall / svelte-apollo

Svelte integration for Apollo GraphQL
MIT License
947 stars 68 forks source link

Add toPromise function to query #38

Closed Hamfor closed 4 years ago

Hamfor commented 4 years ago

What's the problem?

Handling asynchronous calls using {#await promise} blocks is really neat in svelte but unfortunately you can't easily use await when handling the data within your <script> tags or in other contexts.

Solution

Implement a toPromise function for queries that allows you to turn your query observable into a promise in order to use async/await.

Turns this:

query(
    client, 
    { 
      query: THINGS,
    }
  ).subscribe(
    async (res) => {
      const { data } = await res
      // ...
    },
    error => {
      // ...
    }
  )

Into this:

try {
  const { data } = query(
    client, 
    { 
      query: THINGS,
    }
  ).toPromise()
} catch(error) {
  //...
}

Outstanding issues

frederikhors commented 4 years ago

@Hamfor, great! Thank you! How do you unsubscribe today?

frederikhors commented 4 years ago

@Hamfor in my project these lines are called everytime a query is done: https://github.com/timhall/svelte-apollo/blob/master/src/query.ts#L70-L79.

So I think we are already unsubscribing...

Am I wrong?

UPDATE

I am wrong.

subscribe_to_query is to handle.

Hamfor commented 4 years ago

@frederikhors That's the issue since there's no way to unsubscribe after you've retrieved the result of the Promise currently. I had an idea of using nested Promises but I haven't tried it out yet and it's not a very nice solution even if it works

timhall commented 4 years ago

Hi @Hamfor thanks for the PR! Since the query returns an svelte "store", you can perform this functionality by prefixing $ to access the underlying promise:

const things = query(client, { query: THINGS })

// Use $things to access the store's values
$things.then(({ data }) => { console.log(data) })

The above snippet only gets the first value and unsubscribes automatically. To get all the values and re-run a block of code as it changes use $: to mark the statement as reactive:

const things = query(client, { query: THINGS })

// Use $: to mark the statement reactive
// Use $things to access the store's values
$: $things.then(({ data }) => { console.log(data) })

This is part of the beauty of Svelte! Thanks again for the PR

beebase commented 3 years ago

@timhall I don't get this. Code below gives me "Uncaught TypeError: $things.then is not a function"

const things = query(client, { query: THINGS })
$: $things.then(({ data }) => { console.log(data) })