You must implement a network layer that connects to a backend with subscription support. This network layer must implement the following additional method:
sendSubscription: (request: SubscriptionRequest) => DisposableThe SubscriptionRequest object supports:
type SubscriptionRequest {
getQueryString: () => string;
getVariables: () => Variables;
getClientSubscriptionId: () => string;
onNext: (payload: SubscriptionResult) => void;
onError: (error: any) => void;
onCompleted: (value: any) => void;
getDebugName: () => string;
}The getQueryString method returns the GraphQL query string. The getVariables method returns the variables for the query. The getClientSubscriptionId method returns a client-side ID for the subscription.
Call the onNext, onError, and onCompleted methods when the subscription updates.
The return value is expected to conform to:
type Disposable = {
dispose: () => void;
}The dispose method should tear down the subscription.
RelaySubscriptions.Environment extends Relay.Environment and provides subscription support.
This method has the signature:
subscribe: (subscription: Subscription, observer?: Observer) => DisposableThis method will make the subscription.
The observer, if provided, is expected to conform to:
type Observer = {
onNext?: (value: SubscriptionResult) => void;
onError?: (error: any) => void;
onCompleted?: (value: any) => void;
}The specified callbacks will be invoked when the subscription updates. The onNext callback fires after the store update.
Subclass the Subscription class to define a subscription. This base class is similar to Relay.Mutation, except that you need to implement getSubscription instead of getMutation and getFatQuery.
import { Subscription } from 'relay-subscriptions';
export default class WidgetSubscription extends Subscription {
/* ... */
}As with Relay.Mutation, you can construct an instance of a subclass of Subscription with the new keyword and optional props.
new WidgetSubscription({ widget })Define these properties to specify the input data dependencies for the subscription.
This static property defines the subscription's data requirements as a object of fragment builders, as with the fragments static property on Relay.Mutation. These fragments can then be composed elsewhere with MySubscription.getFragment(fragmentName).
static fragments = {
widget: () => Relay.QL`
fragment on Widget {
id
}
},
};If provided, this specifies the default variables for the fragment builders, as with the initialVariables static property on Relay.Mutation.
If provided, this method modifies variables for the fragment builders, as with the prepareVariables static method on Relay.Mutation.
Implement these methods to define the subscription's behavior.
This method should return the concrete subscription query. The query should use the $input variable for the subscription input. Unlike with mutations, this is not a fat query, so it must specify all desired fields. You can compose in fragments from container components here, which can help manage code duplication.
getSubscription() {
return Relay.QL`
subscription {
updateWidget(input: $input) {
${Widget.getFragment('widget')}
}
}
`;
}This method should return the mutation configs, as with the getConfigs method on Relay.Mutation.
getConfigs() {
return [{
type: 'FIELDS_CHANGE',
fieldIDs: {
widget: this.props.widget.id,
},
}];
}This method should return the subscription input variables, as with the getVariables method on Relay.Mutation.
getVariables() {
return {
id: this.props.widget.id,
};
}RelaySubscriptions.createContainer behaves like Relay.createContainer. It provides additional functionality for subscription support.
The specification for a Relay Subscriptions container accepts an optional subscriptions property:
subscriptions?: subscriptionFn[]These subscription functions are expected to have the signature:
type subscriptionFn = (props: Object) => ?Subscription<any>;This function can return a falsy value to indicate that no subscription is desired.
The Relay Subscriptions container will manage these subscriptions. It will establish the subscription after the component mounts, replace any subscriptions that have changed type or variables, and tear down these subscriptions when the component unmounts.
import RelaySubscriptions from 'relay-subscriptions';
/* ... */
export default RelaySubscriptions.createContainer(Widget, {
fragments: {
widget: () => Relay.QL`
fragment on Widget {
# ...
${WidgetSubscription.getFragment('widget')}
}
`,
},
subscriptions: [
({ pending, widget }) => !pending && new WidgetSubscription({ widget }),
],
});The Relay Subscriptions container injects an augmented props.relay to the component with subscription functionality.
This method invokes the subscribe method on the Relay Subscriptions environment. It has the same signature of:
subscribe: (subscription: Subscription, observer?: Observer) => DisposableYou can use this to manually manage the subscription.
import RelaySubscriptions from 'relay-subscriptions';
/* ... */
class Widget extends React.Component {
componentDidMount() {
const { relay, widget } = this.props;
this.subscription = relay.subscribe(
new WidgetSubscription({ widget }),
);
}
componentWillUnmount() {
this.subscription.dispose();
}
/* ... */
}
export default RelaySubscriptions.createContainer(Widget, {
fragments: {
widget: () => Relay.QL`
fragment on Widget {
# ...
${WidgetSubscription.getFragment('widget')}
}
`,
},
});