Skip to content

Commit c8a6df0

Browse files
authored
Merge pull request #18 from molindo/apollo-hooks
Add support for react-apollo@^3.0.0
2 parents e08e7b4 + 001caf5 commit c8a6df0

17 files changed

Lines changed: 2056 additions & 2389 deletions

CHANGELOG.md

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,23 @@
11
# Changelog
2+
3+
## 3.0
4+
5+
### New features
6+
7+
- Support for `@apollo/react-*` packages.
8+
- Export `NetworkStatus` and `OperationError` types for TypeScript users.
9+
10+
### Breaking changes
11+
12+
- Raised required peer dependency version of `apollo-client` to `^2.6.0`.
13+
- You need to depend on a React integration from one of the `@apollo/react-*` packages. See [upgrade guide](https://www.apollographql.com/docs/react/migrating/hooks-migration/).
14+
15+
Special thanks to [Matth10](https://github.com/Matth10), [rcohen-unext](https://github.com/rcohen-unext) and [MasterKale](https://github.com/MasterKale) for beta testing this release in their apps and code review.
16+
217
## 2.0
318

19+
Compatible with `react-apollo@^2`. See [usage instructions](https://github.com/molindo/react-apollo-network-status/tree/e08e7b43e2e3447ec0d9399262d17b162162805e#react-apollo-network-status).
20+
421
### New features
522

623
- Use hooks for reading the network status.
@@ -18,6 +35,12 @@
1835
- The opt-out property `context: {useNetworkStatusNotifier: false}` was renamed to `useApolloNetworkStatus`.
1936
- If you provide a custom reducer, there's now a new signature where you only provide one function which handles action types instead of separate functions. This pattern composes better since you usually have to cover all network events to implement a given feature.
2037

38+
## 1.1
39+
40+
Subscription operations no longer affect the loading property, but they can potentially set the error property (@shurik239 in [#9](https://github.com/molindo/react-apollo-network-status/pull/9)).
41+
2142
## 1.0
2243

23-
Initial stable release
44+
Compatible with `react-apollo@<=2`. See [usage instructions](https://github.com/molindo/react-apollo-network-status/tree/583a00f6344e05edcfee90bee0823a7736f56021#react-apollo-network-status).
45+
46+
Initial stable release.

README.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import React from 'react';
1313
import ReactDOM from 'react-dom';
1414
import {ApolloClient} from 'apollo-client';
1515
import {createHttpLink} from 'apollo-link-http';
16-
import {ApolloProvider} from 'react-apollo';
16+
import {ApolloProvider} from '@apollo/react-common';
1717
import {ApolloNetworkStatusProvider, useApolloNetworkStatus} from 'react-apollo-network-status';
1818

1919
function GlobalLoadingIndicator() {
@@ -42,6 +42,10 @@ const element = (
4242
ReactDOM.render(element, document.getElementById('root'));
4343
```
4444

45+
> **Note:** The current version of this library supports the latest [`@apollo/react-*` packages](https://www.apollographql.com/docs/react/migrating/hooks-migration/). If you're using an older version of React Apollo and don't want to upgrade, you can use an older version of this library (see [changelog](./CHANGELOG.md)).
46+
47+
## Returned data
48+
4549
The hook `useApolloNetworkStatus` provides an object with the following properties:
4650

4751
```tsx
@@ -69,7 +73,6 @@ type OperationError = {
6973

7074
The error objects have the same structure as the one provided by [apollo-link-error](https://github.com/apollographql/apollo-link/tree/master/packages/apollo-link-error). Subscriptions currently don't affect the status returned by `useApolloNetworkStatus`.
7175

72-
7376
Useful applications are for example integrating with [NProgress.js](http://ricostacruz.com/nprogress/) or showing errors with [snackbars from Material UI](http://www.material-ui.com/#/components/snackbar).
7477

7578
## Advanced usage

example/DataFetcher.tsx

Lines changed: 51 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
import React, {useState} from 'react';
1+
import {useQuery} from '@apollo/react-hooks';
22
import gql from 'graphql-tag';
3-
import {Query} from 'react-apollo';
4-
import usePendingPromise from './usePendingPromise';
3+
import React, {useState, useEffect} from 'react';
54

65
type Props = {
76
isBroken?: boolean;
@@ -29,69 +28,60 @@ interface Variables {
2928

3029
export default function DataFetcher({isBroken}: Props) {
3130
const [skip, setSkip] = useState(true);
32-
const [queryPromise, setQueryPromise] = usePendingPromise();
31+
const {data, loading, error, refetch} = useQuery<Data, Variables>(query, {
32+
context: {useApolloNetworkStatus: true},
33+
notifyOnNetworkStatusChange: true,
34+
fetchPolicy: 'network-only',
35+
skip,
36+
variables: isBroken ? undefined : {id: '1'}
37+
});
3338

34-
function onFetch() {
39+
function onFetchClick() {
3540
setSkip(false);
3641
}
3742

38-
return (
39-
<p>
40-
<Query<Data, Variables>
41-
context={{useApolloNetworkStatus: true}}
42-
fetchPolicy="network-only"
43-
onError={error => {
44-
// eslint-disable-next-line no-console
45-
console.error(error);
46-
}}
47-
query={query}
48-
skip={skip}
49-
variables={isBroken ? undefined : {id: '1'}}
50-
>
51-
{({data, loading, error, refetch}) => {
52-
function onRefetchClick() {
53-
const result = refetch();
54-
setQueryPromise(result);
55-
}
43+
function onRefetchClick() {
44+
refetch();
45+
}
46+
47+
function onRetryClick() {
48+
refetch();
49+
}
5650

57-
function onRetryClick() {
58-
refetch();
59-
}
51+
useEffect(() => {
52+
if (error) console.error(error);
53+
}, [error]);
6054

61-
if (skip) {
62-
return (
63-
<span>
64-
Idle{' '}
65-
<button onClick={onFetch}>
66-
{isBroken ? 'Broken fetch' : 'Fetch'}
67-
</button>
68-
</span>
69-
);
70-
}
55+
let content;
56+
if (skip) {
57+
content = (
58+
<>
59+
Idle{' '}
60+
<button onClick={onFetchClick}>
61+
{isBroken ? 'Broken fetch' : 'Fetch'}
62+
</button>
63+
</>
64+
);
65+
} else if (data && data.user) {
66+
content = (
67+
<>
68+
User: {data.user.name}{' '}
69+
<button disabled={loading} onClick={onRefetchClick}>
70+
Refetch
71+
</button>
72+
</>
73+
);
74+
} else if (loading) {
75+
content = 'Loading …';
76+
} else if (error) {
77+
content = (
78+
<>
79+
Error <button onClick={onRetryClick}>Retry</button>{' '}
80+
</>
81+
);
82+
} else {
83+
throw new Error('Unexpected state');
84+
}
7185

72-
return (
73-
<span>
74-
{data && data.user ? (
75-
<span>
76-
User: {data.user.name}{' '}
77-
<button
78-
disabled={queryPromise != null}
79-
onClick={onRefetchClick}
80-
>
81-
Refetch
82-
</button>
83-
</span>
84-
) : loading ? (
85-
'Loading …'
86-
) : error ? (
87-
<>
88-
Error <button onClick={onRetryClick}>Retry</button>
89-
</>
90-
) : null}
91-
</span>
92-
);
93-
}}
94-
</Query>
95-
</p>
96-
);
86+
return <p>{content}</p>;
9787
}

example/DataUpdater.tsx

Lines changed: 21 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
import React, {FormEvent} from 'react';
21
import gql from 'graphql-tag';
3-
import {Mutation} from 'react-apollo';
4-
import usePendingPromise from './usePendingPromise';
2+
import {useMutation} from '@apollo/react-hooks';
3+
import React, {FormEvent, useState} from 'react';
54

65
const mutation = gql`
76
mutation updateUser($id: ID!, $user: UserInput!) {
@@ -27,32 +26,27 @@ interface Variables {
2726
}
2827

2928
export default function DataUpdater() {
30-
const [submissionPromise, setSubmissionPromise] = usePendingPromise<any>();
29+
const [name, setName] = useState('');
30+
const [updateUser, result] = useMutation<Data, Variables>(mutation);
3131

32-
return (
33-
<Mutation<Data, Variables> mutation={mutation}>
34-
{updateUser => {
35-
function onSubmit(e: FormEvent) {
36-
e.preventDefault();
37-
38-
const nameInput = e.currentTarget.children[0];
39-
if (!(nameInput instanceof HTMLInputElement)) {
40-
throw new Error('`name` input not found');
41-
}
32+
function onSubmit(event: FormEvent<HTMLFormElement>) {
33+
event.preventDefault();
34+
updateUser({variables: {id: '1', user: {name}}});
35+
}
4236

43-
const result = updateUser({
44-
variables: {id: '1', user: {name: nameInput.value}}
45-
});
46-
setSubmissionPromise(result);
47-
}
37+
function onNameInputChange(event: FormEvent<HTMLInputElement>) {
38+
setName(event.currentTarget.value);
39+
}
4840

49-
return (
50-
<form onSubmit={onSubmit}>
51-
<input name="name" placeholder="Update user name" type="text" />{' '}
52-
<input disabled={submissionPromise != null} type="submit" />
53-
</form>
54-
);
55-
}}
56-
</Mutation>
41+
return (
42+
<form onSubmit={onSubmit}>
43+
<input
44+
onChange={onNameInputChange}
45+
placeholder="Update user name"
46+
type="text"
47+
value={name}
48+
/>{' '}
49+
<input disabled={result.loading} type="submit" />
50+
</form>
5751
);
5852
}

example/NetworkStatusBoundary.tsx

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,15 @@ export default function NetworkStatusBoundary({children}: Props) {
1010
const [enableBubbling, setEnableBubbling] = useState(false);
1111
const [optIn, setOptIn] = useState(false);
1212

13-
function onBubblingCheckboxChange(e: SyntheticEvent<HTMLInputElement>) {
14-
setEnableBubbling(e.currentTarget.checked);
13+
function onBubblingCheckboxChange(event: SyntheticEvent<HTMLInputElement>) {
14+
setEnableBubbling(event.currentTarget.checked);
1515
}
1616

17-
function onOptInCheckboxChange(e: SyntheticEvent<HTMLInputElement>) {
18-
setOptIn(e.currentTarget.checked);
17+
function onOptInCheckboxChange(event: SyntheticEvent<HTMLInputElement>) {
18+
setOptIn(event.currentTarget.checked);
1919
}
2020

2121
return (
22-
// @ts-ignore False positive which asks for `client` property. This
23-
// prop is injected via a HOC and not needed here.
2422
<ApolloNetworkStatusProvider enableBubbling={enableBubbling}>
2523
<div style={{backgroundColor: '#2368841a'}}>
2624
<div
@@ -48,7 +46,7 @@ export default function NetworkStatusBoundary({children}: Props) {
4846
onChange={onOptInCheckboxChange}
4947
type="checkbox"
5048
/>
51-
Ignore mutation
49+
Ignore mutation loading state
5250
</label>
5351
</div>
5452
</div>

example/NetworkStatusReporter.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import React from 'react';
21
import {Operation} from 'apollo-link';
2+
import React from 'react';
33
import {useApolloNetworkStatus} from '../src';
44

55
type Props = {

example/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1+
import {ApolloProvider} from '@apollo/react-common';
12
import React from 'react';
23
import ReactDOM from 'react-dom';
3-
import {ApolloProvider} from 'react-apollo';
44
import createClient from '../src/__testUtils__/createClient';
55
import DataFetcher from './DataFetcher';
66
import DataUpdater from './DataUpdater';

example/usePendingPromise.ts

Lines changed: 0 additions & 25 deletions
This file was deleted.

0 commit comments

Comments
 (0)