timhall / svelte-apollo

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

Use getClient internally and use result directly (not #await) #43

Closed frederikhors closed 3 years ago

frederikhors commented 4 years ago

@timhall, what do you think if we change things to make it more like @urql/svelte?

From this:

<script>
  import { getClient, query } from 'svelte-apollo';
  import { GET_BOOKS } from './queries';

  const client = getClient();

  const books = query(client, { query: GET_BOOKS });
</script>

{#await $books}
  Loading...
{:then result}
  {#each result.data.books as book}
    {book.title} by {book.author.name}
  {/each}
{:catch error}
  Error: {error}
{/await}

to this:

<script>
  import { query } from '@urql/svelte';
  import { GET_TODOS } from './queries';

  $: todos = query({ query: GET_TODOS });
</script>

{#if $todos.fetching}
  Loading...
{:else if $todos.error}
  Oh no! {$todos.error.message}
{:else}
  <ul>
    {#each $todos.data.todos as todo}
      <li>{todo.text}</li>
    {/each}
  </ul>
{/if}

This can fix https://github.com/timhall/svelte-apollo/issues/19, https://github.com/timhall/svelte-apollo/issues/40 and https://github.com/timhall/svelte-apollo/issues/21.

Already started here: https://github.com/timhall/svelte-apollo/pull/42 but I need help.

roblevintennis commented 4 years ago

First off, thank you for this library. I've been able to successfully populate a list view query, and a login query using it, and I'm really happy to have this adapter allow me to use graphql / apollo in Svelte-land! 💯

So, I was about to create an issue apprehensively as I don't believe my issues are a bug but lack of docs perhaps--but the not #await part of this ticket makes me want to add my 2 cents...

First off the proposal in OP for me doesn't matter too much and feels like it's just a difference between using a Promise vs. a Reactive Svelte variable which seems mostly idiomatic. I think using in a way that strays from the one main template based {#await $books}... way is what's most problematic.

In fact, I was trying to get to the bottom of what's going on with Svelte and/or svelte-apollo with this dollar sign exactly, and why does everything stop working unless you "dereference" the result of your query or mutation result variable?

I scoured the Svelte docs and it looks like there are two general uses of $:

  1. Reactive statements

https://svelte.dev/docs#3_$_marks_a_statement_as_reactive

But this one uses $: foo and, for example, in my app I have something like: $: isListView = viewType === ViewTypes.List; which is nicely reactive such that if any of the dependencies in the conditional check change e.g. viewType then isListView will "react" and change as well. I use this to determine whether to have a toggle have "card view" or "list view" active. But, this doesn't seem to be how svelte-apollo is using dollar (I think).

  1. Prefix stores

https://svelte.dev/docs#4_Prefix_stores_with_$_to_access_their_values

I'm assuming that this must be how svelte-apollo is using this idiom and what gets returned upon something like a query. Essentially, I'm getting some sort of Promise reference to a store e.g. QueryStore.

Reading the return type of QueryStore [here](https://github.com/timhall/svelte-apollo/blob/master/src/query.ts#L34 QueryStore) and the structure def here appears to confirm this although I'm still having trouble fully grok'ing some of that.

All to say, I think some clarification on exactly what's happening with the dollar sign would be extremely helpful in the docs and help folks ramp up more quickly. I'm happy to help with a PR but only if I understand and can write the correct things :-)


I think I should show also how I ultimately used this without using the template example as obviously not every graphql query maps to a result that should be displayed:

export const LOGIN_USER = gql`
  query($email: String!, $password: String!) {
    login(email: $email, password: $password) {
      id
    }
  }
`;

export const loginUser = (email, password) => query(
  getClient(), { query: LOGIN_USER, variables: { email, password } }
);

and then my form submit handler basically does:

    loginResults = loginUser(event.target.email.value, event.target.password.value);
    $loginResults.then(results => {
      if (results.data && results.data.login && results.data.login.id) {
        alert('We got an ID so logged in: ' + results.data.login.id);
      }
    });

So, you see why I needed to figure out that I was dealing with this sort of Promise / store prefix thing in $loginResults :)