-
-
Notifications
You must be signed in to change notification settings - Fork 523
does vue-apollo work with vuex? #7
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
Comments
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? |
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. |
We could either do a vuex plugin or a vuex module I think. |
a plugin would be great for vuex. I have another question though |
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. |
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? |
Why? It doesn't seem like a bad idea to me. |
Any news on this? I'd be happy to help. |
@Akryum, @stubailo This |
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):
What do you think? |
@davenport Please post some example code to demonstrate how this would look in a Todo (or Counter) or similar simple example with Vuex. Cheers! |
@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! |
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?? |
Hi I'm just posting here to say +1 - I'm also very interested in having vuex support. |
I suggest you also have a look at vue-rx with apollo |
@MikeLeonard 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);
}
});
},
} |
Of course, externalise these functions. Otherwise your actions hash will not scale and quickly become an entangled jungle! :P |
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... |
@kristianmandrup , @ykshev |
@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 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!? |
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. |
I have no idea how to handle the |
as far as I understand, the |
ah well, the {
__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 // 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 :) |
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?? |
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
I think the problem with what you are suggesting is described by: |
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 |
Has anyone dug any further on this? Or has everyone been finding the Vue-Apollo solution appropriate? Scott |
interesting discussion... I'm fluid with vuex and learning the graphql paradigm right now. createPost.vue Are there any best practices evolving round vue and graphql/vuex? I'm still new to graphql so still exploring. Thanks. |
We are a few months on and this is still no clearer @beebase What did you end up doing? |
@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. |
@beebase I agree prisma has too many changes in a short amount of time. It hasn't matured enough to fully rely on. |
@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 |
Any news on this? Does plugin for integrating vuex + apollo exist, or something? |
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. :) |
@diguliu - I believe the state management of choice should now be apollo-link-state. Scott |
#384 Seems |
I'm now delving into this solution. I'll report back, once I know how good (or bad) it works. Scott |
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. |
Then you miss the benefits of Apollo client and have to manage all the
state yourself. 😸
Le ven. 9 nov. 2018 à 09:41, Özgür Uysal <notifications@github.com> a
écrit :
… I'm not sure if this was there before but Apollo Link can be used as stand
alone without cache. See the docs here
<https://www.apollographql.com/docs/link/#standalone>. This way you can
build a typical Vue + Vuex application and completely avoid ApolloClient
and InMemoryCache. Of couse in this case you won't be using Vue Apollo
either.
I tested it and it seems to work perfectly.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#7 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ACqyfMYNn5NnUM-oc8-Di_i49gVYRVT6ks5utb5YgaJpZM4KN3-U>
.
|
Isn't that the point of Vuex? |
Yeah but with Apollo client you don't even need Vuex.
Le ven. 9 nov. 2018 à 09:46, Pier Bover <notifications@github.com> a écrit :
… Then you miss the benefits of Apollo client and have to manage all the
state yourself. 😸
Isn't that the point of Vuex?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#7 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ACqyfHCxam4MsYMCuZOaFmHBhbKR3iD2ks5utb91gaJpZM4KN3-U>
.
|
I see... it seems Apollo client is a whole new beast form the last time I checked it. 🤯 |
@Akryum Yes, absolutely. But I'm really not a fan of the way you interact with Apollo cache or apollo-link-state. On the other hand Vuex is so great. EDIT: Having said that, for many projects, using ApolloClient and apollo-link-state as local state management would probably be the best fit as they do eliminate a lot of code for local state management. |
@Akryum - Will Vue-Apollo work with the new Apollo Client 2.5.0 Alpha? Which btw to everyone, now includes link-state. I'd test myself, but have other things to attend to. Just a reassuring "yes" or a disappointing "no" would suffice. 😄 If it is "no", how long do you think it would take until you can get Vue-Apollo updated? Scott |
As this is such a hot discussion it might be a good idea to reflect some of these thoughts on how Vuex does and doesn't integrate with Apollo on the "Local state" part of the documentation? |
@ecker00 i dont get that example. Where is updateHello defined? |
@rnenjoy Neither do I, but I don't have any experience with Apollo and GraphQL yet, so I would not be the right person to update the documentation. |
@ecker00 @rnenjoy you can see example here https://codesandbox.io/s/zqqj82396p and resolvers const is where is it defined |
Hi, You may not need Vuex but what about an application previously written using vuex ? I feel like it is all or nothing. How do you make an existing application using vuex compatible with apollo. We don't really want to switch completely from one to the other otherwise it will break quite a few components. So, we may not need vuex but how could we use it anyway smoothly with apollo such that we don't loose all the benefits from apollo. Do you any code samples we could use as an example ? Regards, |
@Eclar you can keep using Vuex as your central store, but instead of making calls to your REST API with Axios, you just make calls and/or subscriptions with Apollo client and feed Vuex with the responses. I made this example some time ago with an old version of Apollo client. https://github.com/PierBover/vuex-apollo-example-project/blob/master/store.js Don't take this at face value, it's just a quick and dirty example. For a more realistic approach I would put all the GraphQL code outside of Vuex. |
Thank you for the answer. Do we have a good practice for this sort of behaviour ? Maybe @Akryum could clarify ? |
If one were to remove the Vuex dependency and rely solely on vue-apollo's store. Updating the cache on successful data response. What is the recommended way to replace the functionality Vuex getters affords? To apply some logic when accessing previously stored data Say I've a graph query that returns a list of numbers and I'd like to reduce down to a total based on a user input range, or get the value for a matching ID etc. Many thanks! |
@oller - Can you expand on your use case? What kind of component would offer a list of data, to be then reduced to a range or single id? If you need a range, wouldn't that be an input variable to the query to begin with? Scott |
Hey @smolinari , thanks for the response. Sorry that wasn't the best worded example. Lets say I've a query that returns leads...
The state value is a string ID, which can be one of 7 values. Depending on the value of the state I want to apply a contextual css class to set a color for the getClassForLeadState: state => leadState => {
let className
switch (state.leadStates.findIndex(i => i.id === leadState)) {
case 0:
case 1:
className = 'success'
break
case 2:
className = 'warning'
break
case 3:
...
},
getLabelForLeadState: state => leadState => {
return state.leadStates.find(ls => ls.id === leadState).label
},
getTargetTotalForLeadState: state => leadState => {
return state.leads
.filter(lead => lead.state === leadState)
.reduce((prev, current) => prev + current.target, 0)
} How would a scenario like this best be implemented if I was looking to remove Vuex? Multiple components need to be able to access these getters, so I can't just factor this into a single component. Should I factor out a common helper file? look to load this logic into the Apollo store perhaps with @client ? look to move these into separate queries? I could add some of these into new graphQL queries, but I don't want to start adding css presentational classes into the graphQL, that's no use. And it seems crazy to ask for a subset of data again when i've already the whole list and i just want to match against a key/value, but perhaps that's just the graphQL paradigm and i've not totally got my head around it yet. Any input gratefully received! Thanks! |
@oller - not sure this will answer your question completely. But, I think it might get you thinking in a certain direction. Here is a Todo app with client-link-state and also the situation of setting styling, etc. All those "gets" you had before simply aren't needed, once the data is set. Where the data comes from doesn't matter. It just needs to be available and "set", when the component is rendered, either by calling it from a server a file or set in the data prop. After that, it is automatically reactive and that is the beauty of Vue. 👍 https://codesandbox.io/s/k3621oko23 I hope it helps. 😃 Scott |
February 2019 and we still haven't figured this out. (BTW, why is this issue closed?) |
@AnalyzePlatypus - Why not figured out? Apollo Client has its own state management built in and therefore Vuex is not needed at all. My example To-do app above demonstrates this ability. Scott |
Can / should vue-apollo be used with vuex?
If yes then could you please show examples?
The text was updated successfully, but these errors were encountered: