Apollo-client: How to react to external redux action

Created on 8 Dec 2016  路  13Comments  路  Source: apollographql/apollo-client

When using the reducer option in a graphql query we can control and manipulate the store, by reducing redux actions. I was under the impression that it was possible to reduce all redux actions to react on a action outside of Apollo. I found out the reducers function is only called for actions specific to Apollo.

I use a backend that does not support subscriptions yet, so I'm looking to leverage my own websocket connection to implement push updates. But I cannot find a way to inject these updates in Apollo.

Is updating the Apollo state based on external actions somehow possible, and otherwise is this an idea to implement?

Most helpful comment

This seems (on some quick tests) that it'd be an example of using the new read/write APIs from a Redux middleware:

import ApolloClient from 'apollo-client';
import {
  createStore,
  combineReducers,
  applyMiddleware
} from 'redux';
import gql from 'graphql-tag';

const client = new ApolloClient();

function testMiddleware(store) {
  return function(next) {
    return function(action) {
      if (action.type === 'MY_ACTION') {
        client.writeQuery({
          query: gql`
            {
              todo(id: 1) {
                completed
              }
            }
          `,
          data: {
            todo: {
              completed: true
            }
          }
        });
      }
      return next(action);
    };
  };
}

const store = createStore(
  // reducers
  combineReducers({
    apollo: client.reducer()
  }),
  // provide the initial state
  {},
  // Apollo middleware
  applyMiddleware(
    client.middleware(),
    testMiddleware
  )
);

That said, I (in older versions of Apollo) had to have custom Redux actions integrating with the store, but I think one can avoid that entirely with the new read/write API.

All 13 comments

@jfrolich you're right, due to how I implemented result reducers they currently cannot run on non-apollo actions. It's on our roadmap though, and it's something that we want to fix soon. Unless I'm forgetting something, your only option is to update the cache manually or implement a hack on top of the apollo subscriptions network interface (client side only) that lets you fire subscription actions when your other websocket returns data. I think it would work, but it's definitely not very clean, so I don't know if it's a viable option for you.

Hmm after some digging around. How would you go about to update the cache manually. Any function I should look at?

apollostack/react-apollo#367 possibly related?

Maybe I have similar problem: I have component with inputfield and after user submits this input I'd like to validate by graphQl query if data submitted are ok and display green or red message.

Mutations have nice possibility to inject function to the component wrapped by apollo connect that will trigger the mutation (http://dev.apollodata.com/react/mutations.html#calling-mutations function ApolloClient#mutate) , but I didn't find out how to accomplish this for the query (and I don't want to use mutation for query cases).

Would be nice to have something like mutate even for queries, not just mutations.

Hey @helfer

Is this feature scheduled already? It would be a great help for us :)

Thanks,

Daniel

Not sure if this helps, but I use nonApollo actions to update store and therefore state and based on state I can fire queries or mutations within the HoCs that react on the state change.

Just a silly example:

  • socket receives new message, I'd dispatch the action to nonApollo store
  • changes in store are reflected (via mapstateToProps) in my HoC component
  • this component has a graphQl query/mutation that takes this changes and query/mutate accordingly

Because I use compose to wrap my pure components in multiple layers (redux connect, graphql query or multiple queries, Intl), the code is straightforward.

For some cases I wrote small helper that is composable in HoC, too and accepts function that may have side effects (like dispatching or call another query/mutation). I use it to extract side effects triggered by mutation (like save accessToken to localStorage after login mutation is performed).

I can share the code if someone interested.

I think what we really need to do here is implement some kind of method like: client.updateQuery(query, updateFn). Then we solve the problem not only for Redux users, but for people with other state management solutions as well.

+1
would be awesome to have apollo listening to foreign actions.

You can change data in Apollo from external actions with the new read and write APIs! https://dev-blog.apollodata.com/apollo-clients-new-imperative-store-api-6cb69318a1e3#.3993ykbqe

Yeah I think you could do this by creating your own Redux middleware which listens to actions and calls the above read/write methods when necessary.

Yeah I think you could do this by creating your own Redux middleware which listens to actions and calls the above read/write methods when necessary.

Does anyone have an example of doing that?

This seems (on some quick tests) that it'd be an example of using the new read/write APIs from a Redux middleware:

import ApolloClient from 'apollo-client';
import {
  createStore,
  combineReducers,
  applyMiddleware
} from 'redux';
import gql from 'graphql-tag';

const client = new ApolloClient();

function testMiddleware(store) {
  return function(next) {
    return function(action) {
      if (action.type === 'MY_ACTION') {
        client.writeQuery({
          query: gql`
            {
              todo(id: 1) {
                completed
              }
            }
          `,
          data: {
            todo: {
              completed: true
            }
          }
        });
      }
      return next(action);
    };
  };
}

const store = createStore(
  // reducers
  combineReducers({
    apollo: client.reducer()
  }),
  // provide the initial state
  {},
  // Apollo middleware
  applyMiddleware(
    client.middleware(),
    testMiddleware
  )
);

That said, I (in older versions of Apollo) had to have custom Redux actions integrating with the store, but I think one can avoid that entirely with the new read/write API.

Thanks for the example @dahjelle!

Closing this up since it's an old issue and the question has been answered 馃檪

Was this page helpful?
0 / 5 - 0 ratings