react-native-action-cable
react-native-action-cable copied to clipboard
Example Implementation for React-Native/Rails/GraphQl/Apollo
We did not find any solutions for our stack React-Native/Rails/GraphQl/Apollo and specifically had problems creating an ActionCable that connected properly with GraphQL subscriptions. The solution was a combination of this very nice package (thanks @kesha-antonov!!) and adjusting graphql-ruby ActionCableLink to work with the interface of react-native-action-cable
. In case anyone else is having trouble with this stack I thought it might be nice to see a working example. Maybe in the README or example folder etc.
index.js
/**
* @format
*/
import React from 'react';
import { ActionCable, Cable } from '@kesha-antonov/react-native-action-cable';
import { ApolloProvider } from 'react-apollo';
import { ApolloClient } from 'apollo-client';
import { ApolloLink } from 'apollo-link';
import { AppRegistry } from 'react-native';
import { createHttpLink } from 'apollo-link-http';
import { getMainDefinition } from 'apollo-utilities';
import { InMemoryCache } from 'apollo-cache-inmemory';
import AppWithNavigator from './src/navigators';
import { name as appName } from './app.json';
import ActionCableLink from './src/helpers/ActionCableLink';
const httpLink = createHttpLink({ uri: 'http://localhost:3000/graphql' });
const actionCable = ActionCable.createConsumer('ws://localhost:3000/cable');
const cable = new Cable({});
const hasSubscriptionOperation = ({ query }) => {
const { kind, operation } = getMainDefinition(query);
return kind === 'OperationDefinition' && operation === 'subscription';
};
const link = ApolloLink.split(
hasSubscriptionOperation,
new ActionCableLink({ actionCable, cable }),
httpLink
);
const client = new ApolloClient({
link,
cache: new InMemoryCache()
});
const AppWithApollo = () => (
<ApolloProvider client={client}>
<AppWithNavigator />
</ApolloProvider>
);
AppRegistry.registerComponent(appName, () => AppWithApollo);
adjusted ActionCableLink.js
import { ApolloLink, Observable } from 'apollo-link';
const printer = require('graphql/language/printer');
function ActionCableLink(options) {
const { cable, actionCable } = options;
const { connectionParams = {} } = options;
const channelName = options.channelName || 'GraphqlChannel';
const actionName = options.actionName || 'execute';
return new ApolloLink(operation => (
new Observable((observer) => {
const channelId = Math.round(
Date.now() + Math.random() * 100000
).toString(16);
const channel = cable.setChannel(
'GraphqlChannel', // channel name to which we will pass data from Rails app with `stream_from`
actionCable.subscriptions.create({
channel: channelName,
channelId,
...connectionParams
})
);
/* eslint-disable func-names */
channel.on('connected', function () {
this.perform(
actionName,
{
query: operation.query ? printer.print(operation.query) : null,
variables: operation.variables,
operationId: operation.operationId,
operationName: operation.operationName
}
);
}).on('received', function (payload) {
if (payload.result.data || payload.result.errors) {
observer.next(payload.result);
}
if (!payload.more) {
this.unsubscribe();
observer.complete();
}
});
/* eslint-enable func-names */
return channel;
})
));
}
module.exports = ActionCableLink;
@ccfz awesome! Thank you!
This worked for us too, thanks @ccfz!
Thank you @ccfz, this is awesome. Without this, my subscriptions weren't initially connecting without triggering a refresh or navigation in RN. Very strange.
Solution still working in 2022. Thanks a lot!