Skip to content
This repository has been archived by the owner on Apr 13, 2023. It is now read-only.

Add complete handler to Subscription, to handle the case when the ser… #2716

Merged
merged 10 commits into from
Jan 24, 2019
7 changes: 7 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

## vNext

### Improvements

- Adds a `onSubscriptionComplete` prop to the `Subscription` component, that
can be passed a callback to be called when the subscription observable
is completed. <br/>
[@sujeetsr](https://github.com/sujeetsr) in [#2716](https://github.com/apollographql/react-apollo/pull/2716)

## 2.4.0

### Bug Fixes
Expand Down
9 changes: 9 additions & 0 deletions src/Subscriptions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export interface SubscriptionProps<TData = any, TVariables = OperationVariables>
shouldResubscribe?: any;
client?: ApolloClient<Object>;
onSubscriptionData?: (options: OnSubscriptionDataOptions<TData>) => any;
onSubscriptionComplete?: () => void;
children?: (result: SubscriptionResult<TData>) => React.ReactNode;
}

Expand All @@ -55,6 +56,7 @@ class Subscription<TData = any, TVariables = any> extends React.Component<
variables: PropTypes.object,
children: PropTypes.func,
onSubscriptionData: PropTypes.func,
onSubscriptionComplete: PropTypes.func,
shouldResubscribe: PropTypes.oneOfType([PropTypes.func, PropTypes.bool]),
};

Expand Down Expand Up @@ -136,6 +138,7 @@ class Subscription<TData = any, TVariables = any> extends React.Component<
this.querySubscription = this.queryObservable!.subscribe({
next: this.updateCurrentData,
error: this.updateError,
complete: this.completeSubscription
});
};

Expand Down Expand Up @@ -165,6 +168,12 @@ class Subscription<TData = any, TVariables = any> extends React.Component<
});
};

private completeSubscription = () => {
const { onSubscriptionComplete } = this.props;
if (onSubscriptionComplete) onSubscriptionComplete();
this.endSubscription();
};

private endSubscription = () => {
if (this.querySubscription) {
this.querySubscription.unsubscribe();
Expand Down
3 changes: 2 additions & 1 deletion src/test-links.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,11 @@ export class MockSubscriptionLink extends ApolloLink {
});
}

public simulateResult(result: MockedSubscriptionResult) {
public simulateResult(result: MockedSubscriptionResult, complete = false) {
setTimeout(() => {
const { observer } = this;
if (!observer) throw new Error('subscription torn down');
if (complete && observer.complete) observer.complete();
if (result.result && observer.next) observer.next(result.result);
if (result.error && observer.error) observer.error(result.error);
}, result.delay || 0);
Expand Down
31 changes: 31 additions & 0 deletions test/client/Subscription.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,37 @@ it('calls onSubscriptionData if given', done => {
jest.runTimersToTime(40);
});

it('should call onSubscriptionComplete if specified', done => {
jest.useFakeTimers();

let count = 0;

const Component = () => (
<Subscription
subscription={subscription}
onSubscriptionData={() => {
count++;
}}
onSubscriptionComplete={() => {
done();
}}
/>
);

wrapper = mount(
<ApolloProvider client={client}>
<Component />
</ApolloProvider>,
);

const interval = setInterval(() => {
link.simulateResult(results[count], count === 3);
if (count >= 3) clearInterval(interval);
}, 10);

jest.runTimersToTime(40);
});

it('executes subscription for the variables passed in the props', done => {
expect.assertions(4);
const subscriptionWithVariables = gql`
Expand Down