-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
Mobx integration #503
Comments
What kind of integration are you looking for? |
Hi @stubailo! Perhaps an integration example similar to: http://docs.apollostack.com/apollo-client/redux.html Thanks! |
Right, but I'm wondering what integration means to you - is it having the store data live in mobx? using the query results with mobx as data sources? etc. In redux it's pretty clear because we internally use reducers etc. But as far as I know MobX doesn't have reducers so I'm wondering what kind of integration you would be looking for. Right now you can easily just call |
From my point of view, in order to use Apollo together with Mobx we need a way to transform a query result into an observable state tree. This can be done quite easily by wrapping In the end it will be very tighly coupled to your domain model, therefore I am not sure how one could add some generic integration to Apollo. Reading this again, I realize that |
Does MobX rely on having nested trees of observables? Is it not enough to have one observable that returns entire new JSON results? |
@stubailo both work, if it is possible to granular patch the json tree it will just be more efficient, but I think first viable iteration could be to just create fresh observables. I think this should get you going: import {autorun, observable} from "mobx"
import {fromResource} from "mobx-utils"
// generic utility
function queryToMobxObservable(/*apollo observable*/ observable) {
let subscription
return fromResource(
// MobX starts using the observable
(sink) => {
subscription = queryObservable.subscribe({
next: ({ data }) => {
// todo: recycle MobX observables? (yes, will be renamed at some point ;-))
sink(observable(data))
},
error: (error) => {
console.log('there was an error sending the query', error);
}
});
},
// Observable no longer in use (might become in use later again)
() => subscription.unsubscribe()
)
}
// usage
const myObservable = queryToMobxObservable(client.watchQuery(/* apollo query */))
autorun(() => {
console.log("Amount of results: " + myObservable.current().length)
}) |
@stubailo To me having an integration would mean we could swap out the redux core for Mobx. This would save some file weight if one was using Mobx and Apollo (do you happen to know the payload size of Redux btw?) I've found that I really don't need all the hassle of Redux with Apollo Client and for the small amount of "global state" that I need to store, Mobx is more practical. I ended up just making a HoC using However, I realize switching out your cache layer is not going to be simple so i'm ok with just loading Redux as an Apollo dep. |
Was wandering around with mobx-meteor-apollo and found this issue. There is a small misspelling in @mweststrate example, it should be I see here are a lot of people from meteor community, maybe someone could give me a feedback on my integration with react-mobx-meteor-apollo. In my router import ApolloClient from 'apollo-client';
import { meteorClientConfig } from 'meteor/apollo';
const apolloClient = new ApolloClient(meteorClientConfig());
const appStore = new AppStore(apolloClient);
const stores = {appStore, uploadStore};
...
<Provider { ...stores }>
// Mobx provider
</Provider> Than in my export default class AppStore {
@observable user = false;
constructor (apolloClient) {
const handle = apolloClient.watchQuery({
query: gql`
query ($id: String!) {
user(id: $id) {
_id
}
}
`,
variables: {
id: Meteor.userId()
},
forceFetch: false,
returnPartialData: true,
pollInterval: 10000,
});
const query = queryToMobxObservable(handle);
autorun(() => {
if (query.current()) this.setUser(query.current().user)
})
}
@action setUser = (user) => {
this.user = user;
}
} and import {observable} from "mobx"
import {fromResource} from "mobx-utils"
export default function (queryObservable) {
let subscription
//Mobx util https://github.com/mobxjs/mobx-utils#fromresource
return fromResource(
(sink) => {
subscription = queryObservable.subscribe({
next: (graphqlRes) => {
if (graphqlRes.data) {
sink(observable(graphqlRes.data));
}
},
error: (error) => {
console.log('there was an error sending the query', error);
}
});
},
() => subscription.unsubscribe()
)
} any suggestions how to improve all this code above? |
@ykshev thanks, great start. How would you do things like Cheers! |
@harrisrobin actually I've moved from mobx Now I call mobx action onRouter Enter and my action looks like this @action getData = (collectionId) => {
this.isLoading = true;
const options = {
query: gql`
query collectionItem($userId: String!, $id: String!, $limit: Int!, $offset: Int!, $isFavorite: Boolean) {
collection(userId: $userId, id: $id ) {
_id,
title,
isPublic,
images(limit: $limit, offset: $offset, isFavorite: $isFavorite) {
_id
title
collectionId
image {
url
width
height
}
}
}
`,
variables: {
userId: Meteor.userId(),
id: collectionId,
limit: this.limit,
offset: this.offset,
isFavorite: this.isFavoriteFiltered,
},
// forceFetch: true
}
const self = this,
apolloClient = this.appStore.apolloClient;
this.query = apolloClient.watchQuery(options);
this.subscription = this.query.subscribe({
next(result, more) {
if (!result.loading) {
self.setData(result.data.collection);
}
},
error(err){
self.appStore.createNotification({
type: 'error',
id: Date.now(),
text: 'Something went wrong on querying. ' + err.message
})
if (Meteor.isDevelopment) console.log(err);
}
})
} in this case when you have your query saved, you can use fetchMore in another action as this @action loadMore = () => {
if (this.isLoading) return;
this.offset = this.offset + defaults.load;
this.setLoading(true)
this.query.fetchMore({
variables: {
limit: this.limit,
offset: this.offset,
},
updateQuery: (previousResult, { fetchMoreResult, queryVariables }) => {
const prevEntry = previousResult.collection;
const newImages = fetchMoreResult.data.collection.images;
return {
collection: Object.assign({}, prevEntry, {images: [...prevEntry.images, ...newImages] })
};
}
}).then(() => this.setLoading(false))
} and onRouter Leave I call: @action onLeave = () => {
...
this.query = null;
this.subscription = null;
} and I'm still not sure, that I'm doing it in the best optimized way, but having a lack of information about all that stuff, I hope it will be usefull for someone 🖖 |
@ykshev seems a little weird to do this to me. I think i'm simply going to use redux for this project and have to refactor it all... :P Thank you for the help though! |
Let's continue all store API discussions in #1432. |
Just published a small utility mobx-apollo that makes this petty straightforward. |
@sonaye Link is 404 atm :( |
Hi!
I was wondering is there a => How integrate with Mobx example?
Thanks in advance!
The text was updated successfully, but these errors were encountered: