apollographql / apollo-client

:rocket:  A fully-featured, production ready caching GraphQL client for every UI framework and GraphQL server.
https://apollographql.com/client
MIT License
19.37k stars 2.66k forks source link

Using redux-observable #1842

Closed ghost closed 7 years ago

ghost commented 7 years ago

I read almost entirely the apollo client docs and I couldn't find anything on using redux-observable with it.

I know the usual way to make queries with apollo is with the connect() method connecting the query and the class but with redux-observable, you need to be able to call the query/mutation directly in the epic which is in a different js file.

Basically we would have to call the query in the epic and if it's successful, update redux store and return the query information received to the component. Else we would return nothing. I see no way of doing this in my current implementation because only the component knows the query.


Do you guys have already thought about a way you could integrate redux-observable with apollo or is it on hold for now?

Thank you

(First time posting an 'issue')

helfer commented 7 years ago

Hi @vincentpageau, congratulations on filing your first issue! 😉

I think you should be able to do exactly what you want by declaring the query or mutation as a variable, using it in the component and also exporting it from the file. Then in your epic you simply have to import your client instance and the query, and you'll be able to call client.query({ query: myQuery }) or client.mutate({ ... }) and the cache will be updated automatically for you when the result comes back.

I hope this helps, let us know if you have any more questions!

ghost commented 7 years ago

@helfer Thanks for the quick answer !

So far I've been using ApolloProvider to provide my client instance to my entire application. To my knowledge, only my containers and components have access to that client instance and my actions/epics do not.

Would you suggest I do not provide the client in ApolloProvider and instead create it in its own js class and import it everywhere I use it?

Also, when you say

using it in the component

, you mean using connect() to connect the query to the class?

stubailo commented 7 years ago

@vincentpageau that's right, you can just import your client instance into the place where you want to use it. The provider is specifically so that you can use the graphql container.

However, if you are doing server side rendering make sure you make a new client instance for every render - that's one of the main uses of the provider, is to avoid conflicts.

ghost commented 7 years ago

@stubailo Ok I understand a lot more now but I still don't have all the information I need to correctly make query calls and mutations from my epics/action creators (not you guys' fault, I'm new to both apollo and redux)

If I take for example my mutation. At the moment, it's in my class where I call my action creator. I use the graphql method to connect it to my class and pass props when I call my actionCreator. There, I use props.mutate and it calls my mutation.

you can just import your client instance into the place where you want to use it

To stop using the method above, I guess I need to import a new client instance in my actionCreator and do the mutation with is but then how do I use it?

Thank you And if there are docs that explain this well, feel free to link them. I couldn't find any, that's why I'm asking here.

ghost commented 7 years ago

Ok I successfully changed the actionCreator logic to mutate using the client directly.

import { client } from '../../services/network'          //new client instance
import { languageMutation} from '../mutation'     //mutation to do (using gql)
import { changeLanguageFulfilled, changeLanguageError} from '../actions/navigationBarActions';    //import actions to use in the epic

export const languageEpic = (action$) => {
  return action$.ofType('CHANGE_LANGUAGE')
    .mergeMap(action => client.mutate({
      mutation: languageMutation,
      variables: { id: action.id,  defaultLanguage: action.selected_language, defaultTimeZoneId: action.selected_timeZone }
    }).then(result => changeLanguageFulfilled(result))
      .catch(error => changeLanguageError(error))
  );
};

I use return here to call my reducer and then update my redux store.

Thank you for your help 😃

loganpowell commented 6 years ago

@vincentpageau sorry to ping on such an old thread, but I was hoping to find out how your approach (above) has worked out for you after you've had some time to use this pattern.

vpageau commented 6 years ago

@loganpowell It's not a problem. Yes this approach has worked out fine so far. I recommend it to anyone using both apollo-client and redux-observable together.