Code Monkey home page Code Monkey logo

Comments (115)

Akryum avatar Akryum commented on April 27, 2024 37

We could either do a vuex plugin or a vuex module I think.

from apollo.

Akryum avatar Akryum commented on April 27, 2024 35

That's what I meant with "examples soon". 😉

from apollo.

Akryum avatar Akryum commented on April 27, 2024 23

(Note) Apollo Client 2.x will allow replacing redux with vuex. See this

from apollo.

kristianmandrup avatar kristianmandrup commented on April 27, 2024 20

@DougDavenport Yes!

Some mind experiments for how it could look.

Mutations

// apollo/mutations.js

export const addTag = (state, newTag) => {
  this.$apollo.mutate({
    // Query
    mutation: gql`mutation ($label: String!) {
      addTag(label: $label) {
        id
        label
      }
    }`,
    // Parameters
    variables: {
      label: newTag,
    },
    // Update the cache with the result
    // 'tagList' is the name of the query declared before
    // that will be updated with the optimistic response
    // and the result of the mutation
    updateQueries: {
      tagList: (previousQueryResult, { mutationResult }) => {
        // We incorporate any received result (either optimistic or real)
        // into the 'tagList' query we set up earlier
        return {
          tags: [...previousQueryResult.tags, mutationResult.data.addTag],
        };
      },
    },
    // Optimistic UI
    // Will be treated as a 'fake' result as soon as the request is made
    // so that the UI can react quickly and the user be happy
    optimisticResponse: {
      __typename: 'Mutation',
      addTag: {
        __typename: 'Tag',
        id: -1,
        label: newTag,
      },
    },
  })
}

Queries

// apollo/subscriptions.js
export const projectList = rootState.apollo.watchQuery({
    query: gql`
      query projectsList{
        projects {
          _id
          name
        }
      }
    `,
  })

Subscription services

import { * as subscriptions } from './apollo/subscriptions'
import store from './store'

export getProject = () => {
  subscriptions.projectList.subscribe({
    next: (result) => {
      const projects = result.data.projects || [];
      store.dispatch('setProjects', projects)
    },
    error: (error, done) => {
      console.log('there was an error sending the query', error);
    }
  });
}

Actions

// apollo/actions.js

import { * as mutations } from './apollo/mutations'

export const addTag = ({ commit, state, rootState }) {
    mutations.addTag(state.newTag)
    .then((data) => {
        // commit to VueX store with confirmation result from server
        commit('addTag', data)
    }).catch((error) => {
      // Error
      console.error(error);

      // Restore the initial newTag??
      commit('clearTag')
    });
  }

const setProjects = ({ commit, state, rootState }) => {
  commit('setProjects', state.projects)
}

Actions

// actions.js

import { addTag, getProject } from './apollo/actions'

export const actions = {
  increment ({commit}) {
    commit('increment')
  },
  addTag,
  getProject
}

Mutations

// mutations.js

export const mutations = {
  increment (state, n) {
    // mutate state
    state.count = state.count + n
  },
  setProjects: (state, projects) {
    state.projects = projects
  },
  addTag: (state, newTag) {
    state.tags.push(newTag)
  },
  clearTag: (state) {
    state.newTags = ''
  }
}

State

// state.js
const state = {
  count: 1,
  tags: [],
  newTag: '',
  projects: []
}

Then export actions, mutations and state from ./config.js

import { actions, mutations, state } from './config'

const store = new Vuex.Store({
  state,
  mutations,
  actions
  }
})

As the example above demonstrates, it would be best to follow the @ykshev architecture proposal of putting the logic in an action, so mutations are kept "clean".

Note: I'm still a novice with Vue2, Apollo and VueX. I'm I on the right track here!?

from apollo.

PierBover avatar PierBover commented on April 27, 2024 16

I've created this simple example project. Hope it is useful for someone.

https://github.com/PierBover/vuex-apollo-example-project

from apollo.

microcipcip avatar microcipcip commented on April 27, 2024 10

@Akryum I think it would be beneficial to have a demo/boilerplate that shows GraphQL integration with Vue+Vuex, because it seems quite complex to set up, as there are many libraries involved: apollo client, vue-apollo, vue-supply, vuex

from apollo.

DougDavenport avatar DougDavenport commented on April 27, 2024 9

Vue, Vuex, Apollo, and GraphQL are new technologies for me so I hesitate to comment on specifics. My investigations so far lead me to believe this combo may be productive. The Vuex API is at https://vuex.vuejs.org/en/api.html . I'm hoping these can work together.

from apollo.

Akryum avatar Akryum commented on April 27, 2024 8

You can now use vue-supply with vue-apollo to use apollo data in your vuex store easily. I'll make some examples soon.

from apollo.

dohomi avatar dohomi commented on April 27, 2024 7

I use both in the same project.. here some example code to login:

mixins/vueMixins.js

const fetchUser = {
    beforeCreate () {
        const store = this.$store;
        return new Promise((resolve, reject) => {
            if (store.state.authUser) {
                resolve();
            } else {
                return store
                    .dispatch('getUser')
                    .catch(e => console.log(e));
            }
        });
    }
};

export default {
    fetchUser
};

store/actions.js

/**
 *
 * @param {String} commit
 * @returns {Promise}
 */
export const getUser = ({commit}) => new Promise((resolve, reject) => {
    apolloClient
        .query({
            query: user,
            forceFetch: true
        })
        .then(({data}) => {
            const r = data && data.user;
            commit(types.SET_USER, r || null);
            return resolve(r);
        })
        .catch(er => reject(er));
});

store/index.js

import * as actions from './actions';

const store = new Vuex.Store({
    
    state: {
        authUser: null
    },

    mutations: {
        [types.SET_USER]: (state, user) => {
            state.authUser = user;
        }
    },
    actions
});

export default store;

plugins/apolloClient.js

import Vue from 'vue';
import VueApollo from 'vue-apollo';
import ApolloClient, {createNetworkInterface} from 'apollo-client';

const apolloClient = new ApolloClient({
    networkInterface: createNetworkInterface({
        uri: apolloUri,
        transportBatching: true
    }),
    dataIdFromObject: r => r.id
});

Vue.use(VueApollo, {apolloClient});

Inside of *.vue files I just use the apollo for queries or this.$apollo for mutation callbacks. Works very well so far for me.

from apollo.

stephan281094 avatar stephan281094 commented on April 27, 2024 6

Any news on this? I'd be happy to help.

from apollo.

mikelnrd avatar mikelnrd commented on April 27, 2024 6

Hi I'm just posting here to say +1 - I'm also very interested in having vuex support.

from apollo.

RichAyotte avatar RichAyotte commented on April 27, 2024 6

A Vue component's concerns should be:

  • Visual representation of data
  • Input interface

It should not be concerned with:

  • Where the data came from such as a remote server, cached, local event, hardware sensor, single or multiple sources etc.
  • How it was fetched such as REST, GraphQL, Socket, RPC etc

If you can guarantee that data that your component is using will always be accessed via GraphQL and it only comes from a single source then you're fine. If you can't, a store abstraction will keep your components lighter, more modular, more easily testable and it will greatly reduce the refactoring effort when the data source changes.

from apollo.

microcipcip avatar microcipcip commented on April 27, 2024 5

Why is it so complex to integrate GraphQL with Vuex? Is it because you're trying to have it reactive (for example when polling from the database?)

What if I just want to fetch the data on page load and then fetch it again when I change route? Do I still have to use this library for that, or I could just use Apollo Client + Vuex, get the promise and return the JSON from vuex?

Edit: of all the solutions above, do you know which one work best and has the smallest footprint?

from apollo.

beebase avatar beebase commented on April 27, 2024 5

interesting discussion... I'm fluid with vuex and learning the graphql paradigm right now.
I can see the points made about attaching queries to components vs vuex actions and I think both approaches have their advantages, however...
Looking at this example of a mutation with apollo client directly inside a component makes me wonder. Do we really have to write this "mess" in order to link component data to graphql??

createPost.vue
Just looking at one field "description", you need to do stuff in line 43,44,47,53,61,64. That's ridiculous. Imagine having 5 or 10 fields. I suppose this could be reduced with graphql 'fragments', but still, this doesn't feel right. If this is really the only way to link vue components to graphql, I'd rather stick to vuex and maybe use graphql inside vuex actions.

Are there any best practices evolving round vue and graphql/vuex? I'm still new to graphql so still exploring. Thanks.

from apollo.

PierBover avatar PierBover commented on April 27, 2024 4

I'm just starting to figure this out. I have experience with Vue/Vuex but barely starting to use Apollo.

First a couple of points:

  1. Doing API calls directly in the components is an anti pattern. Doesn't matter if we are considering REST or GraphQL.
  2. When using Vuex, all queries to an API have to be done in the store actions since these can be async. Store mutations have to be sync.

Any solution that involves integrating Apollo and Vue properly means that it has to allow for integration with Vuex, and most importantly Vuex modules.

Considering all this, it seems to me the solution is simply to move GraphQL queries and GraphQL mutations to store actions, and then create actions for subscribing and unsubscribing to GraphQL resources.

Can anyone explain why this approach is not valid?

from apollo.

Ben52 avatar Ben52 commented on April 27, 2024 4

Related: https://www.apollographql.com/docs/link/links/state.html

Its not vuex, but you can manage all your application's state in graphql's cache using the new apollo-link-state.

from apollo.

diguliu avatar diguliu commented on April 27, 2024 4

After reading this whole thread I feel like I learned a lot and still have no idea of what's the proper way to do this. :)

from apollo.

xpepermint avatar xpepermint commented on April 27, 2024 3

@Akryum, @stubailo This vuex-apollo thing is really bugging me and as I can see I'm not alone :). Would you be so kind and help us find a proper solution for vuex? I think/hope you are the right people to ask. It would also be great to join forces and have this topic described at dev.apollodata.com. Thanks.

from apollo.

davenport avatar davenport commented on April 27, 2024 3

After reviewing vue-apollo, apollo client, and vuex I think there may be an easy way to enhance vue-apollo to allow for vuex support. Currently vue-apollo updates the local state. In vuex the store is modified by committing a mutation.

What if a new option were added to vue-apollo to bypass the local state update and instead call a user supplied function?

Let's call the new option "apply" (or whatever makes more sense). The following updated applyData should be enough to allow support for vuex (or something else):

function applyData(data) {
  loadingDone();

  if (typeof options.apply === 'function') {
    options.apply.call(vm, data);
  } else if (typeof options.update === 'function') {
    vm[key] = options.update.call(vm, data);
  } else if (data[key] === undefined) {
    console.error(`Missing ${key} attribute on result`, data);
  } else {
    vm[key] = data[key];
  }

  if (typeof options.result === 'function') {
    options.result.call(vm, data);
  }
}

What do you think?

from apollo.

ykshev avatar ykshev commented on April 27, 2024 3

@MikeLeonard
Isn't it enough? Just pass your apollo client to the root store, and then:

  actions: {
    $GET_PROJECTS: ({ commit, state, rootState }) => {
      return rootState.apollo.watchQuery({
        query: gql`
          query projectsList{
            projects {
              _id
              name
            }
          }
        `,
      }).subscribe({
        next: (resulut) => {
          const projects = resulut.data.projects || [];
          commit('SET_PROJECTS', projects)
        },
        error: (error, done) => {
          console.log('there was an error sending the query', error);
        }
      });
    },
}

from apollo.

Akryum avatar Akryum commented on April 27, 2024 3

vue-supply is useful for both queries and subscriptions. Mutations can be done outside without​ problem.

from apollo.

PierBover avatar PierBover commented on April 27, 2024 3

There is no need of using vue-apollo if you want to use Vuex.

Using the vanilla apollo-client is just simpler for integrating with Vuex by following the exact same patterns you'd use with Axios, fetch, or any other HTTP library.

from apollo.

PierBover avatar PierBover commented on April 27, 2024 3

And what I think @PierBover is proposing and I think is better:
View <-> Store <-> Server

Yes. That's how Vuex was designed. Precisely to decouple the front end data layer from the front end presentation layer.

Source

Edit:

From what I understand, Jing proposes:
View -> Server -> Store -> View

This is coupling your data layer with your presentation layer. If you do this with a typical REST API, then one day you might want to switch to GraphQL and you will be forced to modify all your components. Next year you will want to switch to GraphQL 2 or whatever comes, same problem.

Another problem of this approach is that any logic related to communicating to the API will be spread on all your components. That code won't be reusable and it will become an unmaintainable jungle. Instead of having all your data layer code in one nice place, you will have dozens of duplicated pieces across your project.

Edit 2:

The relevant part of the video start at https://youtu.be/9sc8Pyc51uU?t=12m45s or the lifecycle proposed at https://youtu.be/9sc8Pyc51uU?t=14m31s

Redux (from where Vuex took the inspiration) is precisely designed to solve this problem, and was released a couple of months after this talk.

from apollo.

PierBover avatar PierBover commented on April 27, 2024 3

Hey @microcipcip I've updated my example with subscriptions.

https://github.com/PierBover/vuex-apollo-example-project

from apollo.

RichAyotte avatar RichAyotte commented on April 27, 2024 3

@PierBover That's not quite what I said. Apollo Client abstracts the centralized state manager and it is this abstraction that I'm in favour of. It automatically manages the central state from the provided GraphQL queries. Also Apollo Client only works with remote data so I'm very much in favour of using Vuex for local shared state.

I would like to eventually write something like:

const remoteApolloClient = new ApolloClient({
    networkInterface: createNetworkInterface({ uri: '/api/graphql'})
})

const localApolloClient = new ApolloClient({
    store: new Vuex.Store({...})
})

const apolloProvider = new VueApollo({
    clients: {
        remoteApolloClient
        , localApolloClient
    }
})

from apollo.

dohomi avatar dohomi commented on April 27, 2024 2

I just would like to chip in here: the greatest joy might be, if vue-apollo uses vuex internally and the $apollo component is pushing the states internal into namespaced vuex states.. So the whole vue-apollo might get syntactic sugar and behind the scenes @PierBover approach would happen. Not sure if I'm on the wood way though

from apollo.

RichAyotte avatar RichAyotte commented on April 27, 2024 2

It took me a month of using Apollo Client with Vuex to realize that I was wrong about putting GraphQL queries in a Vuex store. I understand now why queries belong in components. There's nothing like experience to help one understand.

Apollo Client has its own store which it manages so copying that data into Vuex store actually removes many of the benefits that Apollo offers such as optimized fetching, caching, and updating its local data store automatically but most importantly query validation.

How confident would you be about dropping the property of an object in a Vuex store? How would you know which components depend on it? With GraphQL, it's simple, just use something like eslint-plugin-graphql and know immediately which components you broke.

Vuex's purpose is to simplify local state management. GraphQL's purpose is to simplify foreign state management. They're different for the moment. What I would like to see is the ability to use GraphQL for local state management as well. In other words, I'd like to query the Vuex store with GraphQL. Has anyone done this?

from apollo.

PierBover avatar PierBover commented on April 27, 2024 2

I'll just leave this quote by Eric Elliott here and unsubscribe from this issue since I really have nothing more to add:

Mingling data fetching, data manipulation and view render concerns is a recipe for time-traveling spaghetti.

Source

from apollo.

smolinari avatar smolinari commented on April 27, 2024 1

I've been sort of fanning the fire on these debates and for the push to Vuex and I will admit, I've done too little otherwise and I apologize for that.

It seems to me though, especially with Vue 2.0 now using a virtual DOM, and in a sense working more like React, that a direct integration of Vue and Apollo (like with what we have here) is going to work just fine. In other words, we don't need Vuex anymore, as its flux type of system was built mainly for the type of reactivity Vue 1.0 offered. Remember, my fanning the need for Vuex integration was being done in the Vue 1.0 days. 😄

I welcome the more conceptual discussion on this. Where are the cutting points between Apollo and Vue, which aren't possibly working quite right? Or is everything ok, as I suspect it is?

Scott

from apollo.

microcipcip avatar microcipcip commented on April 27, 2024 1

@Akryum This is amazing :)

from apollo.

Samuell1 avatar Samuell1 commented on April 27, 2024 1

@kristianmandrup i think there is something used with apollo and vuex https://github.com/vuejs/vue-curated-client

from apollo.

smolinari avatar smolinari commented on April 27, 2024 1

I hope I am not misunderstanding the direction of this conversation, but, isn't the whole idea of GraphQL and componentizing the queries (i.e. having the queries with the components) why it was created in the first place? I mean, that was one of its main selling points, when Facebook first open sourced it.

Let me ask this as a question. How can components be portable and properly reusable, when their data fetching (or mutating) code is placed in some depths of a different area of the application?

Here is the video from 2015 describing what I mean:

https://www.youtube.com/watch?v=9sc8Pyc51uU

The part with Jing explains the developer experience I'm talking about. That's not to say, for complex components, everything should be on one file, but certainly, the query code should be with the component someway, somehow. 😄

Scott

from apollo.

smolinari avatar smolinari commented on April 27, 2024 1

You are talking about UI input validation, not data validation.

Please explain what you mean, but in terms of using GraphQL. There must be something I'm not understanding, which I'd most definitely like to.

I already faced the challenge of doing queries with Firebase on a couple of medium sized React projects.

As I said. I wouldn't do queries in components with REST either. There isn't a client side library built for it, as GraphQL is (i.e. with componentization in mind).

If you can guarantee that data that your component is using will always be accessed via GraphQL and it only comes from a single source then you're fine.

If there are multiple sources needed for an application, they are irrelevant for the client with GraphQL, because the backend would have the task of ingesting any external APIs. So, if the app is using GraphQL, it will always have only one single endpoint. That's one of the main selling points as to why Meteor wanted GraphQL in their tool belt.

GraphQL is a query language especially built for UI developers. It's made to be aligned with components. It's a paradigm change.

Edit- Btw, I'm working with a project called Quasar, which uses Vue and I've started a very basic GraphQL wrapper. This is going to be enhanced considerably over the next couple of months. Keep an eye out for it. 😄

Scott

from apollo.

Akryum avatar Akryum commented on April 27, 2024 1

I see the value for subscriptions, but why not write regular queries in store actions though?

For example, everything in Apollo is Observable-based, which means you could refetch some data somewhere in your app, and all the component that somewhat consumes the same data get updated. So this "subscription" model is still usefull in some cases, even if there are no real-time/subscription data behind.

from apollo.

SebT avatar SebT commented on April 27, 2024 1

Hi,

I'm about to integrate apollo in a vue / vuex app. Even if I'm relatively new to vue, I come from react / redux so the migration isn't that hard. But I've just begun a few days ago to learn GraphQL & Apollo for my new job. So you may notice I struggle a bit to fully grasp the apollo / graphQL paradigm.

My first instinct, as @RichAyotte and @PierBover argued, would be to use the vanilla apollo client with vuex. But after reading the whole thread, and now that I understand that apollo uses redux under the hood, duplicating the redux state into vuex feelds very dirty...

@RichAyotte, you seem to have changed your mind about all GrapqhQL queries going through vuex actions (which is how I would do it). So what would be your approach now? Would you use vue-apollo directly in "smart", higer level components and pass the data down the component tree? Without using Vuex at all for graphql data? Or would you use vue-supply?

@Akryum, you talked about making an example, I've found your demo at vue conf with vue + vuex + vue-supply + vue-apollo. From vue-supply's doc, I understand that it's used to "proxy" apollo's redux state with vuex getters, instead of duplicating data. This way we can still use the vuex store as the global state management tool for our app, which is nice. Am I getting it right ?

I'll try to understand how vue-supply works by starting to implment it into my project and see what it really does.

from apollo.

SebT avatar SebT commented on April 27, 2024 1

@RedShift1 yes. At least that's what I do.

And when I need to interact with data from apollo in vuex I just store their ids in the store. Then, in my components, I use these ids to do apollo queries & mutations, that can make use of the apollo cache.

from apollo.

beebase avatar beebase commented on April 27, 2024 1

@alajfit I sticked to vuex and I'm using it as a local offline database that syncs with a socketio / arangodb server. I LOVE the reactivity and the way you can store data in vuex.

Regarding graphql. I still feel there's a lot of code overhead needed on the client side to keep offline data in sync with the server. Also building the resolvers serverside is a LOT of work, although prisma and hasura.io look promising. Eventually I think I'll switch to graphql once products like apollo, prisma and hasura have evolved more and are settled.

from apollo.

smolinari avatar smolinari commented on April 27, 2024 1

@diguliu - I believe the state management of choice should now be apollo-link-state.

Scott

from apollo.

smolinari avatar smolinari commented on April 27, 2024 1

I'm now delving into this solution. I'll report back, once I know how good (or bad) it works.

Scott

from apollo.

ozguruysal avatar ozguruysal commented on April 27, 2024 1

I'm not sure if this was there before but Apollo Link can be used as stand alone without cache. See the docs here. This way you can build a typical Vue + Vuex application and completely avoid ApolloClient and InMemoryCache. Of course in this case you won't be using Vue Apollo either.

I tested it and it seems to work perfectly.

from apollo.

stubailo avatar stubailo commented on April 27, 2024

This is something that would need to be integrated into apollo-client core. What is the VueX API like, especially for integrations? For Redux we ship a special reducer and middleware, does VueX have similar integration points?

from apollo.

mygnu avatar mygnu commented on April 27, 2024

a plugin would be great for vuex. I have another question though
can i use the apollo store for storing client generated data that doesn't require to sync with server? if yes how would i go about it?

from apollo.

stubailo avatar stubailo commented on April 27, 2024

Usually people do that by using Redux with Apollo Client. So part of your store is managed by AC (the server stuff) and the rest with regular Redux.

So integrating with VueX would mean that AC would manage the server-side data, and you manage the rest as usual.

from apollo.

mygnu avatar mygnu commented on April 27, 2024

I have never used Redux in vue, but vuex. at the moment my app is ok with managing local stuff in components but if there i a chance of vuex plugin for vue-apollo i will wait?
another option is to use bouth vuex and apollo client which is a bit of overkill in my view

from apollo.

stubailo avatar stubailo commented on April 27, 2024

another option is to use bouth vuex and apollo client which is a bit of overkill in my view

Why? It doesn't seem like a bad idea to me.

from apollo.

kristianmandrup avatar kristianmandrup commented on April 27, 2024

@davenport Please post some example code to demonstrate how this would look in a Todo (or Counter) or similar simple example with Vuex. Cheers!

from apollo.

kristianmandrup avatar kristianmandrup commented on April 27, 2024

@DougDavenport As I understand your example, this would work for incoming data to be fed into the store and thus force a new VDOM render phase.

methods: mapActions(...actions), // where actions includes: increment(counter)
apollo: {
  // Query with parameters
  ping: {
    query: ...,
    ...
    apply: (data) => {
      // emit as a Vuex action, that is subscribed to //
      // action then turned into a store mutation on local Vuex store...
      this.increment(data)
    }
  }

Would it make sense to go the other way? ie. for local mutations on store to also potentially cause a side effect of a graphQL mutation? I think it should only be unidirectional, as you would otherwise get into a lot of sync problems, just like with two-way data binding, ie. database/state sync in general. So this truly looks like an elegant flexible solution :)

Note: I'm very new to this, so syntax/understanding might be totally off the tracks!

from apollo.

mygnu avatar mygnu commented on April 27, 2024

while we are using the redux store under the hood with apollo as I understand, is it possible to access and set data to it in vue??

from apollo.

kristianmandrup avatar kristianmandrup commented on April 27, 2024

I suggest you also have a look at vue-rx with apollo
Awesome!

from apollo.

kristianmandrup avatar kristianmandrup commented on April 27, 2024

Of course, externalise these functions. Otherwise your actions hash will not scale and quickly become an entangled jungle! :P

from apollo.

kristianmandrup avatar kristianmandrup commented on April 27, 2024

On another note, we need a system to avoid the "two-way sync" problem. Ie. the above example is for mutating local AND external store. Then you might also have listeners to external store, that contain changes from other users (and your self). So I guess you need to ensure you don't infinitely loop... ie, you need a commit hash or sth to identify mutations you have performed before and skip them? Your thoughts...

from apollo.

davenport avatar davenport commented on April 27, 2024

@kristianmandrup , @ykshev
As I was trying to think through an example of using vuex and vue-apollo together, it seemed to make more sense to just use the apollo client directly with vuex. Is that what you are suggesting?

from apollo.

kristianmandrup avatar kristianmandrup commented on April 27, 2024

However, perhaps VueX should be made better suited to subscription models? What do other socket solutions integrate with VueX? I think there should be a separate apollo subscription Service, which when it receives data performs an action on VueX, which is committed.

from apollo.

kristianmandrup avatar kristianmandrup commented on April 27, 2024

I have no idea how to handle the optimisticResponse with Vuex. Any ideas? Somehow when we do a store.dispatch from the component we need to "catch it" there and do a fake UI update until we get a full cycle roundtrip with state update and re-render ?

from apollo.

kristianmandrup avatar kristianmandrup commented on April 27, 2024

as far as I understand, the action can return a promise, so if the optimisticResponse could resolve the promise it's all good :)

from apollo.

kristianmandrup avatar kristianmandrup commented on April 27, 2024

ah well, the optimisticResponse it just a fake response which would then be fed into the VueX store/state.

{
        __typename: 'Mutation',
        submitComment: {
          __typename: 'Comment',
          // Note that we can access the props of the container at `ownProps`
          postedBy: ownProps.currentUser,
          createdAt: +new Date,
          content: commentContent,
        },

The __typename is apollo specific metadata, which I guess could be ignored.

// from a component action handler method (f.ex activated by button 'add' click) 
store.dispatch('addTag', newTag)
  .then((fakeResponse) -> {
  this.tags = fakeResponse.tags
  })
  .catch(err => this.handleError(err))

Sweet :)

from apollo.

mygnu avatar mygnu commented on April 27, 2024

Why are trying to have two sore management systems redux (used by apollo under the hood) and puting vuex on top of it. Why can't we access the internal redux store for local state? am I missing something here??
See issue here

from apollo.

davenport avatar davenport commented on April 27, 2024

Good question that I have asked myself. It may be possible but vuex is a reactive store that integrates with vue components.

https://vuex.vuejs.org/en/getting-started.html

At the center of every Vuex application is the store. A "store" is basically a container that holds your application state. There are two things that makes a Vuex store different from a plain global object:

  1. Vuex stores are reactive. When Vue components retrieve state from it, they will reactively and efficiently update if the store's state changes.
  2. You cannot directly mutate the store's state. The only way to change a store's state is by explicitly committing mutations. This ensures every state change leaves a track-able record, and enables tooling that helps us better understand our applications.

I think the problem with what you are suggesting is described by:

https://vuex.vuejs.org/en/intro.html

from apollo.

smolinari avatar smolinari commented on April 27, 2024

Has anyone dug any further on this? Or has everyone been finding the Vue-Apollo solution appropriate?

Scott

from apollo.

dohomi avatar dohomi commented on April 27, 2024

HI @smolinari I'm using vue-apollo without any issues. For vuex I am using the npm apollo client directly - which works as well very good so far.

from apollo.

smolinari avatar smolinari commented on April 27, 2024

@dohomi - are you using both in the same project? Or in different projects?

Can you share some example code on how you are using Vuex with the apollo client directly?

Scott

from apollo.

smolinari avatar smolinari commented on April 27, 2024

@Akryum - Awesome stuff! 👍

But, do I understand correctly, vue-supply only hooks into the subscription system of Apollo? How about normal queries and mutations? Will they also work? And will it still be possible to add queries, mutations and now subscriptions directly into components?

Scott

from apollo.

kristianmandrup avatar kristianmandrup commented on April 27, 2024

@Akryum Been reading through some of your examples and docs in project Readme, but would really like to see an example project or tests using it. Cheers!

from apollo.

zeeshanjan82 avatar zeeshanjan82 commented on April 27, 2024

thanks @Samuell1 I think this might be an example to have to vue + apollo + vuex. I really would like to take benefit of all three.

from apollo.

RichAyotte avatar RichAyotte commented on April 27, 2024

@PierBover That's exactly how I'm using Vue, Vuex and Apollo atm and it feels right.

from apollo.

PierBover avatar PierBover commented on April 27, 2024

@RichAyotte are you using vue-apollo or simply vanilla Apollo client?

from apollo.

RichAyotte avatar RichAyotte commented on April 27, 2024

vue-apollo

from apollo.

RichAyotte avatar RichAyotte commented on April 27, 2024

You're right! All those queries and mutations belong in the store, not the components unless the app was simple and didn't use a store.

Glad you brought it up. When I found vue-apollo, I assumed it was the right tool and it was I until Vuex was introduced.

Looks like my components are going on a diet.

from apollo.

RichAyotte avatar RichAyotte commented on April 27, 2024

The relevant part of the video start at https://youtu.be/9sc8Pyc51uU?t=12m45s or the lifecycle proposed at https://youtu.be/9sc8Pyc51uU?t=14m31s

From what I understand, Jing proposes:
View -> Server -> Store -> View

And what I think @PierBover is proposing and I think is better:
View <-> Store <-> Server

from apollo.

microcipcip avatar microcipcip commented on April 27, 2024

@PierBover in your github example if the database is updated am I right in assuming that it won't update the component so you need some kind of polling mechanism?

from apollo.

PierBover avatar PierBover commented on April 27, 2024

Correct @microcipcip but there's no need for polling, you can use subscriptions.

If I have time later I will implement those in my example but the idea is that you'd need an action to activate a subscription and another to deactivate it.

You could want for example to keep the subscription open no matter which components are using the data. For example imagine you have a chat in your application you might want to keep on receiving chat messages even when you are not showing the chat component to the user.

Of course your server has to support subscriptions. Graphcool has subscriptions enabled by default.

Here is the document from Apollo Server on how to implement those on Node:
http://dev.apollodata.com/tools/graphql-subscriptions/index.html

from apollo.

microcipcip avatar microcipcip commented on April 27, 2024

@PierBover I see, let me know if you add that example then, I couldn't remember they were called subscriptions ;p

from apollo.

smolinari avatar smolinari commented on April 27, 2024

This is coupling your data layer with your presentation layer.

It's coupling data requests and mutations with the UI, yes, as queries. And I'd only do it with GraphQL. I'd never do this with REST, because REST isn't made for componentized requests or rather, getting it there would a royal PITA, if it's even possible.

Next year you will want to switch to GraphQL 2 or whatever comes, same problem.

I highly doubt the spec will change that greatly.

That code won't be reusable and it will become an unmaintainable jungle. Instead of having all your data layer code in one nice place, you will have dozens of duplicated pieces across your project.

I disagree. The queries are completely reusable along with the component. Only the queries that are called for in a "page" (i.e. a root component for the page and its children) are requested. There isn't really any duplication, unless you have tons of similar components, which I'd then question your programming.

Think about this. If you want to change a component and add or remove properties/ data, then you'd just update the component and its GraphQL queries. Everything that needs to be changed is there front and center in one place. That is a win in my book.

What is the use of having a query language that can be componentized, if you don't use it that way?

Scott

from apollo.

PierBover avatar PierBover commented on April 27, 2024

I highly doubt the spec will change that greatly.

That's what people said 2 years ago when they were building stuff with REST.

Think about this. If you want to change a component and add or remove properties/ data, then you'd just update the component and its GraphQL queries. Everything that needs to be changed is there front and center in one place. That is a win in my book.

That's a naive approach since you are only considering reading data. When writing it gets more interesting since you need to take into account validation.

Are you going to do validation in your components too?

What is the use of having a query language that can be componentized, if you don't use it that way?

Well... a) What makes you think moving your queries outside of the presentation components is not componentizing your queries? and b) GraphQL is (as it's name implies) purely a query language, just like SQL. It's agnostic on how you use it.

from apollo.

smolinari avatar smolinari commented on April 27, 2024

That's a naive approach since you are only considering reading data.

Um, no I'm not. Form components need mutation queries for sure.

Are you going to do validation in your components too?

Absolutely -> https://github.com/monterail/vuelidate

What makes you think moving your queries outside of the presentation components is not componentizing your queries?

As long as the queries used for the component are in the same file or in a file with the component, i.e. so I can call everything as a single UI component, that is componentized in my mind. Anything else isn't.

Scott

from apollo.

PierBover avatar PierBover commented on April 27, 2024

Absolutely -> https://github.com/monterail/vuelidate

You are talking about UI input validation, not data validation. And yeah, you could move the problem to the API but if you are doing anything moderately serious you are going to need to validate on the client too.

Anyway, it's cool. Use whatever works for you.

I already faced the challenge of doing queries with Firebase on a couple of medium sized React projects. My initial approach was exactly what you are defending, and it was a complete failure in the long run.

from apollo.

RichAyotte avatar RichAyotte commented on April 27, 2024

@PierBover thanks for your input, it has been thought provoking for me at least.

Just to be clear. I now believe that the query belongs in the component, not in the store because queries are rarely shared between components. It is the data that's shared, not the queries. Queries are usually written specifically for each component.

The View <-> Store <-> Server pattern is still correct and is still the one that I'm using. None of that has changed.

Also my arguments about where the data comes from and how it's fetched can still be reconciled with this pattern because instead of standardising on a particular store such as Vuex, I'm standardising the language to query the data. The resolver functions now become responsible for the lower level data locating and fetching work.

I'm thinking now that there might be a way to write GraphQL resolvers in Vuex which would let me query everything in GraphQL. Until then, I'm happy to query Vuex's store with plain ol` JavaScript and lodash and use GraphQL for server side data.

Here's another quote from that article.

Side side note: Relay and Falcor are other interesting solutions for state management, but unlike Redux and MobX, they must be backed by GraphQL and Falcor Server, respectively, and all Relay state corresponds to some server-persisted data. AFAIK, neither offers a good story for client-side-only, transient state management. You may be able to enjoy the benefits of both by mixing and matching Relay or Falcor with Redux or MobX, differentiating between client-only state and server-persisted state. Bottom line: There is no clear single winner for state management on the client today. Use the right tool for the job at hand.

from apollo.

smolinari avatar smolinari commented on April 27, 2024

I'm thinking now that there might be a way to write GraphQL resolvers in Vuex

There are no resolvers in the GraphQL client, are there?

Scott

from apollo.

smolinari avatar smolinari commented on April 27, 2024

I don't understand your comment @PierBover. The usage of Redux and/ or Vuex (i.e. the Flux architecture) with Vue is to undo the time-traveling spaghetti.

Scott

from apollo.

yhhwpp avatar yhhwpp commented on April 27, 2024

so , I can not use the vuex in vue-apollo now?

from apollo.

Samuell1 avatar Samuell1 commented on April 27, 2024

@yhhwpp vue-apollo is only binding, they need to integrate other stores in apollo-client, because still if you save data from apollo-client in vuex they are still in redux store

from apollo.

PierBover avatar PierBover commented on April 27, 2024

I don't understand your comment @PierBover. The usage of Redux and/ or Vuex (i.e. the Flux architecture) with Vue is to undo the time-traveling spaghetti.

Precisely, since @RichAyotte is arguing in favor of not using Vuex (or any other centralized state manager) and making GraphQL queries directly in the components.

from apollo.

PierBover avatar PierBover commented on April 27, 2024

Apollo Client abstracts the centralized state manager and it is this abstraction that I'm in favour of.

Well no because Apollo Client is not a state manager. Its concern is actually related to the network layer of your application. Sure it has a cache but you cannot use it to centralise application state or inject custom logic to manipulate data.

What if you have a product basket and want to update the little number in the basket icon from the top navigation bar when a user adds a product from the products list component?

What if you want to do some data manipulation on the list of products received from the server? Say you want to extract the available colors for some other component that allows you to filter your product list based on those colors.

Apollo Client has no way of solving those situations (nor it shouldn't).

I would agree that a component should be responsible for managing its own internal state, but once you enter into application state realm you need a state manager which Apollo Client isn't.

from apollo.

smolinari avatar smolinari commented on April 27, 2024

I would agree that a component should be responsible for managing its own internal state, but once you enter into application state realm you need a state manager which Apollo Client isn't.

Now I understand where I was missing your point. Now I've got it. 😄

Have you used Vue-Supply yet?

Scott

from apollo.

PierBover avatar PierBover commented on April 27, 2024

Have you used Vue-Supply yet?

No I haven't but it looks very noice and it makes sense:

Apollo Client / Firebase / Meteor / Ably / Whatever <-> Vue-Supply <-> Vuex <-> Vue components

I see the value for subscriptions, but why not write regular queries in store actions though?

Thanks for the suggestion btw, I just noticed I missed it in previous comments...

😝

from apollo.

RichAyotte avatar RichAyotte commented on April 27, 2024

Hi @SebT,

Each component contains GraphQL queries that describe the remote data needed for that component as vue-apollo was designed and contains Vuex references for local shared data. No data is ever passed directly between component otherwise you'd be binding the components, undoing modularity and creating a complicated mess.

The querying language for Vuex is JavaScript which works fine with a bit of help from lodash but less declarative than GQL. Standardising on GQL for all queries, local and remote, would be very nice.

from apollo.

SebT avatar SebT commented on April 27, 2024

Ok @RichAyotte so now you use vue-apollo directly from components. And still use vuex for app local state, as usual.

So the data requested with vue-apollo is bound to the component and never ends up in the vuex store because vue-apollo is designed to get data for a specific view, not the whole app, right?

from apollo.

RichAyotte avatar RichAyotte commented on April 27, 2024

@SebT Yes, exactly.

from apollo.

smolinari avatar smolinari commented on April 27, 2024

That's good news. Thanks Guillaume!

Scott

from apollo.

njreid avatar njreid commented on April 27, 2024

Great stuff. Apollo is reduced to the role of humble query fetcher at the moment in my Vuex app, which offends the sensibilities of both myself and Apollo itself.

from apollo.

RedShift1 avatar RedShift1 commented on April 27, 2024

After reading through all of this I'm confused what the preferred method is. Do I have this right?

  • Handle all data queries (fetch, mutations, etc...) directly using vue-apollo
  • Handle all the rest through vuex

from apollo.

alajfit avatar alajfit commented on April 27, 2024

We are a few months on and this is still no clearer
I still don't feel confident with using vue-apollo on a large scale application
@PierBover would you still recommend the Vuex/ Apollo approach ?

@beebase What did you end up doing?

from apollo.

maarteNNNN avatar maarteNNNN commented on April 27, 2024

@beebase I agree prisma has too many changes in a short amount of time. It hasn't matured enough to fully rely on.

from apollo.

Samuell1 avatar Samuell1 commented on April 27, 2024

@beebase You dont need to write that mess, its more like that example is writed more simplier way to understand. I recommed to look at more actual/complex examples like this: https://github.com/Akryum/vue-summit-app

from apollo.

triesa avatar triesa commented on April 27, 2024

Any news on this? Does plugin for integrating vuex + apollo exist, or something?

from apollo.

ecker00 avatar ecker00 commented on April 27, 2024

#384 Seems apollo-link-state becomes a replacment for vuex. Any drawbacks to this approach?

from apollo.

Akryum avatar Akryum commented on April 27, 2024

from apollo.

PierBover avatar PierBover commented on April 27, 2024

Then you miss the benefits of Apollo client and have to manage all the state yourself. 😸

Isn't that the point of Vuex?

from apollo.

Akryum avatar Akryum commented on April 27, 2024

from apollo.

PierBover avatar PierBover commented on April 27, 2024

I see... it seems Apollo client is a whole new beast form the last time I checked it.

🤯

from apollo.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.