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

[feature request] consider a new API to work with the new vue function-base API? #687

Closed
beeplin opened this issue Jul 3, 2019 · 33 comments

Comments

@beeplin
Copy link

beeplin commented Jul 3, 2019

@Akryum Any plans to publish a new function-based API like useQuery useMutation? ;)

@Akryum
Copy link
Member

Akryum commented Jul 16, 2019

Yes.

@Akryum Akryum closed this as completed Jul 16, 2019
@Akryum Akryum reopened this Jul 16, 2019
@Austio
Copy link
Contributor

Austio commented Aug 7, 2019

@Akryum would you accept a pr for this?

@Akryum
Copy link
Member

Akryum commented Aug 23, 2019

I'm working on it already. 😉

@Austio
Copy link
Contributor

Austio commented Aug 23, 2019

@Akryum was riffing on this last weekend, has a really rough working example for useQuery, would need to handle setting array/objects but i think it is what we would need. Repo is here
https://github.com/Austio/vue-apollo-hooks/tree/master/demo

Working useQuery function: https://github.com/Austio/vue-apollo-hooks/blob/22584e45e1858fb25ad2f0fe16b5671eb0fc9bc9/demo/pages/useQuery.vue#L20

Usage in setup is here: https://github.com/Austio/vue-apollo-hooks/blob/22584e45e1858fb25ad2f0fe16b5671eb0fc9bc9/demo/pages/useQuery.vue#L56

Template has example of the subscribed data and a step to manually pull from the apollo client.

@bbugh
Copy link
Contributor

bbugh commented Oct 3, 2019

@Akryum do you have a branch yet for the new composition useQuery etc? I've experimented with some of our components recently but 90% of them are graphql-driven and I'm curious to try it.

@andremsantos
Copy link

Really looking forward for this. I can't get my hands on using the composition API since basically all of my components use graphql. Thanks for your hard work @Akryum

@csmikle
Copy link

csmikle commented Oct 17, 2019

I see it's in use already (your links here plus the File Explorer example). How do I get to use it? The linked repo appears to be a nuxt demo app, so I just grab the src/index.ts I guess?

@TheJoeSchr
Copy link

Hi there,

does anyone by any chance have a current example of ts + vue-apollo + composition-api (+nuxt) lying around?

I'm currently trying to cobble together at nuxt starter using postgraphile and want to use Typescript, vue-composition-api and vue-apollo & nuxt + a nuxt-postgraphile module, I created for it (with a lot of help of Benjie (from graphile ) and Atinux (from nuxt)).

I spent way too much time trying to get it to work, but I just don't know how e.g. to make TS not complain about the apollo{} in createComponent(). I feel once I passed this initial hurdle it would be a clear highway.

I'm talking about using it like this:

<script lang="ts">

import {
  SetupContext,
  computed,
  createComponent,
  reactive,
} from "@vue/composition-api";

import { SharedLayoutQuery } from "@app/graphql";

export default createComponent({
  name: "DefaultLayout",
  apollo: {
    // Simple query that will update the currentUser
    currentUser: SharedLayoutQuery,
  },
  components: {
[..]  
  },
  setup(_props, ctx: SetupContext) {
    const state = reactive({
      title: "No title",
      isLoggedIn: computed(() => {//check currentUser from apollo}),
    });

    return { ... toRefs(state) };
  },
});
</script>

@TheJoeSchr
Copy link

I looked in the File Explorer example mentioned by @csmikle (I assume it's this one I found via search engine: https://gist.github.com/Akryum/05964e81d09fb5088b7769cff15f5e7c ).

It seems apollo {} is dead? and we should use useQuery and mutate manually instead?

@mihailtd
Copy link

I looked in the File Explorer example mentioned by @csmikle (I assume it's this one I found via search engine: https://gist.github.com/Akryum/05964e81d09fb5088b7769cff15f5e7c ).

It seems apollo {} is dead? and we should use useQuery and mutate manually instead?

Well, I would love to, but Module '"../../node_modules/vue-apollo/types"' has no exported member 'useQuery'. Did you mean to use 'import useQuery from "../../node_modules/vue-apollo/types"' instead? 😄

@TheJoeSchr
Copy link

TheJoeSchr commented Nov 25, 2019

Then maybe we have to work around it by getting it from ctx.root

Like @Austio does in his example: https://github.com/Austio/vue-apollo-hooks/blob/22584e45e1858fb25ad2f0fe16b5671eb0fc9bc9/demo/pages/useQuery.vue#L25 posted above

Edit: or even better, use this file: https://github.com/Austio/vue-apollo-hooks/blob/master/src/index.js

@TheJoeSchr
Copy link

So this is what I cobbled together so far to get it running with TS, but now it seems I'm at the end of my TS knowledge.
@Austio: would you mind taking a look at it? I basically mixed together your plugins/apollo-boost , src/index.js and demo/.../useQuery.vue

I get this error in my Compiler: Type 'Ref<null>' is not assignable to type 'TData'. 'Ref<null>' is assignable to the constraint of type 'TData', but 'TData' could be instantiated with a different subtype of constraint '{}'.

at this part

 return {
    // ...toRefs(state),
    data, error, loading, networkStatus, partial, stale
  };

// full code:

<script lang="ts">
import {
  SetupContext,
  computed,
  createComponent,
  // reactive,
  ref,
  toRefs,
} from "@vue/composition-api";
import gql from "graphql-tag";
import ApolloClient, {
  ApolloCurrentQueryResult,
  ApolloError,
  ApolloQueryResult,
  FetchMoreOptions,
  FetchMoreQueryOptions,
  NetworkStatus,
  ObservableQuery,
  OperationVariables,
  WatchQueryFetchPolicy,
  WatchQueryOptions,
} from "apollo-client";
import { DocumentNode } from "graphql";
import { ApolloClientMethods } from "vue-apollo";
import { ApolloError } from "apollo-client";
import { GraphQLError } from "graphql";

const SharedLayoutQuery = gql`
  query SharedLayout {
    currentUser {
      id
      ...SharedLayout_User
    }
  }

  fragment SharedLayout_User on User {
    id
    name
    username
    avatarUrl
    isAdmin
    isVerified
  }
`;

export interface QueryWatchResult<TData>
  extends Pick<
    ApolloCurrentQueryResult<undefined | TData>,
    "error" | "errors" | "loading" | "partial" | "stale"
  > {
  data?: TData;
  // networkStatus is undefined for skipped queries or the ones using suspense
  networkStatus: NetworkStatus | undefined;
}
// function useQuery({ query, context }) {
function useQuery<
  TData = any
  // TVariables = OperationVariables
  // TCache = object
>(
  query: DocumentNode,
  context: ApolloClientMethods
): QueryWatchResult<undefined | TData> {
  // const state = reactive({
    const data= ref(null);
    const error= ref(null);
    const loading= ref(true);
    const networkStatus= ref(null);
    const partial= ref(null);
    const stale=ref(null);

  // });
  const q = <ObservableQuery>context.root.$apollo.watchQuery({
    query,
  });
  q.subscribe({
    next(result: any) {
      console.log(result);
      data.value = result.data;
      loading.value = result.loading,
      networkStatus.value = result.networkStatus,
      partial.value = result.partial,
      stale.value = result.stale,
    },
    error(error: any) {
      error = error;
    },
  });
  // query: q,
  return {
    // ...toRefs(state),
    data, error, loading, networkStatus, partial, stale
  };
}

export default createComponent({
  name: "DefaultLayout",
  components: {
[...]
  },
  setup(_props, ctx: SetupContext) {
    const state = reactive({
      title: "No title",
      currentUser: useQuery(SharedLayoutQuery, ctx),
    });

    return { state };
  },
});
</script>

@Austio
Copy link
Contributor

Austio commented Nov 26, 2019

@JoeSchr updated with latest api here.

Austio/apollo-hooks-vue@d38e486

@Akryum wdyt? I think this is pretty doable but would be a biggish breaking change. Probably would also be easier to maintain test/utils if we moved to this api and keep a branch for the old method of doing things.

@TheJoeSchr
Copy link

@Austio Thanks a lot for your quick response. I will try it out tomorrow.

I suppose since there is not standardized API yet, it's pretty fruitless to convert it into TS? Or maybe my TS kung fu is just to low to turn watchQuery's result into appropriate TS? (apolloState in your new example). Wdyt?

@alexsserban
Copy link

@JoeSchr updated with latest api here.

Austio/vue-apollo-hooks@d38e486

@Akryum wdyt? I think this is pretty doable but would be a biggish breaking change. Probably would also be easier to maintain test/utils if we moved to this api and keep a branch for the old method of doing things.

That looks awesome, but it fails for something like Nuxt, if you want to pull the data on server side, while the current vue-apollo implementation with the smart queries doesn't.

@Akryum
Copy link
Member

Akryum commented Nov 27, 2019

Support of composition API for serverPrefetch is not implemented yet.

@Austio
Copy link
Contributor

Austio commented Dec 2, 2019

Ii'm sure we will get this in vue-apollo sometime due to Guillaume Chau's work on composition api having ssr support . In the meantime i have a working example that has what i think is a good interface that we can build on and works on the client. I'm going to be using this on a production side project i'm working on to sus out any edges.

https://github.com/Austio/apollo-hooks-vue/blob/master/src/useQuery.js
Going to publish it roughly under apollo-vue-hooks so that we can have some iteration on this in the community before we decide on the api that is needed. Still needs a lot of work, held off on ts interfaces atm, prs welcome for useSubscription and useMutation, with any luck i may get to those this week though.

Use https://v4.apollo.vuejs.org/guide-composable/setup.html

@Akryum
Copy link
Member

Akryum commented Dec 2, 2019

Sorry, I overlooked closing this as it's available already.

@Akryum Akryum closed this as completed Dec 2, 2019
@bbugh
Copy link
Contributor

bbugh commented Dec 2, 2019

🎉🎉🎉 @Akryum I'm really liking the API so far, seems very well thought out. Thank you for this.

FYI to others, you need at least "@vue/composition-api": "^0.3.3" to use @vue/apollo-composable.

@Austio
Copy link
Contributor

Austio commented Dec 2, 2019

Agreed dropped in and works like a charm @Akryum thank you!

@csmikle
Copy link

csmikle commented Dec 2, 2019

@Akryum Does useQuery still accept a gql file instead of an inline gql template string?
I don't think I see this mentioned in the doc

It would have been nice if there was a way to avoid the second step of useResult to get at the object you want inside result (assuming you only had one)

@Akryum
Copy link
Member

Akryum commented Dec 2, 2019

Does useQuery still accept a gql file instead of an inline gql template string?
I don't think I see this mentioned in the doc

Yes

It would have been nice if there was a way to avoid the second step of useResult to get at the object you want inside result (assuming you only had one)

I though about this and couldn't come up with a nice API that didn't feel too magical

@beeplin2
Copy link

beeplin2 commented Dec 2, 2019

@Akryum useQuery and useSubscription have three parameters (document, variables, options) but useMutation has only two (document, options), and variables is in options. Why that? Wouldn't it be better to make them all the same?

Personally I would like to avoid the null in the middle of arguments like useQuery(gql, null, { fetchPolicy }), so I prefer the two-parameter way.

@Akryum
Copy link
Member

Akryum commented Dec 3, 2019

useQuery and useSubscription have three parameters (document, variables, options) but useMutation has only two (document, options), and variables is in options. Why that? Wouldn't it be better to make them all the same?

I went this way because I've found you rarely need the options (other than the document and the variables) for queries and subscriptions, whereas mutations you almost always put some options (such as update and optimisticResponse).
Also useMutation works quite differently compared to useQuery and useSubscription in the sense that it's not reactive and that you can pass the variables when calling mutate.

@TheJoeSchr
Copy link

Thanks for working on this!

I tried to hook it into my Nuxt app, but I get I get this Error doing it: TypeError: composition_api_1.getCurrentInstance is not a function
What I did was adapting "Connect Apollo Client to Vue" from the docs:

import { provide } from '@vue/composition-api'
import { DefaultApolloClient } from '@vue/apollo-composable'

const app = new Vue({
  setup () {
    provide(DefaultApolloClient, apolloClient)
  },

  render: h => h(App),
})

into this, which get's loaded as a plugin by nuxt as startup.

//plugins/vue-apollo-composable.js

import { DefaultApolloClient } from '@vue/apollo-composable'
// import { provide } from '@vue/composition-api'

export default ({ app }, provide) => {
  const apolloClient = app.apolloProvider.defaultClient;
  app.DefaultApolloClient = apolloClient;
  // provide(DefaultApolloClient, apolloClient)
  // inject('myInjectedFunction', string => console.log('That was easy!', string))
}

I adapted this example from the nuxt docs about inject in root & context:
https://nuxtjs.org/guide/plugins#inject-in-root-amp-context

I checked that app.apolloProvider.defaultClient is already populated (by @nuxtjs/apollo ).

I stepped through it and it's this line that triggers it:

//node_modules/@vue/apollo-composable/dist/useQuery.js
function useQuery(document, variables, options) {
...
26:     var vm = composition_api_1.getCurrentInstance();
...
}

What can I try to make it work?

@bbugh
Copy link
Contributor

bbugh commented Dec 4, 2019

@JoeSchr: getCurrentInstance was added to the composition API in 0.3.3.

FYI to others, you need at least "@vue/composition-api": "^0.3.3" to use @vue/apollo-composable.

https://github.com/vuejs/composition-api/releases/tag/v0.3.3

• Expose getCurrentInstance for advanced usage in Vue plugins

@TheJoeSchr
Copy link

TheJoeSchr commented Dec 4, 2019

Fixed it, after reading @Austio message, I thought putting @vue/composition-api at latest would be enough, but it stayed on 0.3.2

-    "@vue/composition-api": "latest",
+    "@vue/composition-api": "^0.3.3",

@Akryum
Copy link
Member

Akryum commented Dec 4, 2019

@TheJoeSchr
Copy link

TheJoeSchr commented Dec 4, 2019

maybe because I'm using yarn workspaces I didn't see the warning. Or there are so many warnings that I oversaw it. Sorry for the noise!

@TheJoeSchr
Copy link

Sorry to bother you guys again, but I'm now trying for hours and hours to get my apolloClient into the root instance on an Nuxt installation.
Problem is, I can't call provide() like in example outside of a VueComponent::setup, so I have no Idea how I can make it available for inject(DefaultApolloClient) in @vue/apollo-composable/src/useApolloClient.ts

I created a plugin (according to nuxt docs) and this is the stuff I tried. It seems either _provided doesn't stick after this function or with the inject method even though I convert it to a string, there is always a $ concatenated, so it would be $_provided

import { Plugin, Context } from '@nuxt/types'
import { DefaultApolloClient } from "@vue/apollo-composable";

const DefaultApolloClientStr:string = DefaultApolloClient.toString();
const DollarDefaultApolloClientStr:string = `$${DefaultApolloClientStr}`;

declare module 'vue/types/vue' {
  interface Vue {
    _provided: any
 }
}
declare module '@nuxt/types' {
  interface Context {
    _provided: any
  }
}

const vueApolloComposable: Plugin = (ctx: Context, inject: (key: string, value: any) => void) => {
  debugger;
  const apolloClient = ctx.app.apolloProvider.defaultClient;
  const provided: {[k: string]: any} = {};
  provided.DefaultApolloClient = apolloClient
  ctx._provided = provided ;
  inject(DollarDefaultApolloClientStr, apolloClient);
  Vue.prototype._provided = provided;
}

export default vueApolloComposable

I also tried accessing it via alternative ctx.app.provide approach, which I found described a little bit hidden in the RFC

Can someone who is more experienced help me out please?

@Austio
Copy link
Contributor

Austio commented Dec 5, 2019

Hey @JoeSchr the best place for this question imo is the Vue forum, second best would be stack overflow. Could you please post over there and copy the link here so that others finding this can follow and I can help there?

@TheJoeSchr
Copy link

TheJoeSchr commented Dec 5, 2019

@Austio gladly:
https://stackoverflow.com/questions/59198021/

@SilentDepth
Copy link

Sorry if I'm making noise, but I wonder why @vue/apollo-composable internally accesses Apollo client instances through inject?

I mean, when I need to send a request in a router guard, I can't use the compositions since they can only be called directly inside a component's setup(). The only option I have seems to use the raw ApolloClient API. Mostly this is not a big problem, but being able to use the compositions makes me feel better. I don't see the reason not to make it this way. Could someone elaborate on the API design?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests