Skip to content

Commit 7374c2b

Browse files
adrienthieryRaúl Gómez Acuña
authored and
Raúl Gómez Acuña
committed
Added ability to check connectivity regularly (#32)
1 parent bd7222f commit 7374c2b

File tree

4 files changed

+62
-26
lines changed

4 files changed

+62
-26
lines changed

README.md

+12-9
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
Handful of utilities you should keep in your toolbelt to handle offline/online connectivity in React Native. It supports both iOS and Android platforms. You can leverage all the functionalities provided or just the ones that suits your needs, the modules are conveniently decoupled.
66

7-
Check out [this medium article](https://blog.callstack.io/your-react-native-offline-tool-belt-795abd5f0183) to see the power of the library with real world examples! 🚀
7+
Check out [this medium article](https://blog.callstack.io/your-react-native-offline-tool-belt-795abd5f0183) to see the power of the library with real world examples! 🚀
88

99
## Contents
1010

@@ -28,7 +28,7 @@ Check out [this medium article](https://blog.callstack.io/your-react-native-offl
2828
## Motivation
2929
When you are building your React Native app, you have to expect that some users may use your application in offline mode, for instance when travelling on a Plane (airplane mode) or the underground (no signal). How does your app behaves in that situation? Does it show an infinite loader? Can the user still use it seamlessly?
3030

31-
Having an offline first class citizen app is very important for a successful user experience. React Native ships with `NetInfo` module in order to detect internet connectivity. The API is pretty basic and it may be sufficient for small apps but its usage gets cumbersome as your app grows. Besides that, it only detects network connectivity and does not garantee internet access so it can provide false positives.
31+
Having an offline first class citizen app is very important for a successful user experience. React Native ships with `NetInfo` module in order to detect internet connectivity. The API is pretty basic and it may be sufficient for small apps but its usage gets cumbersome as your app grows. Besides that, it only detects network connectivity and does not guarantee internet access so it can provide false positives.
3232

3333
This library aims to gather a variety of modules that follow React and redux best practises, in order to make your life easier when it comes to deal with internet connectivity in your React Native application.
3434

@@ -40,6 +40,7 @@ This library aims to gather a variety of modules that follow React and redux bes
4040
- **A step further than `NetInfo` detecting internet access besides network connectivity**
4141
- Offline queue support to automatically re-dispatch actions when connection is back online or **dismiss actions based on other actions dispatched (i.e navigation related)**
4242
- Typed with Flow
43+
- Check connectivity regularly (optional)
4344

4445
## Installation
4546

@@ -74,6 +75,7 @@ type Config = {
7475
timeout?: number = 3000,
7576
pingServerUrl?: string = 'https://google.com',
7677
withExtraHeadRequest?: boolean = true,
78+
checkConnectionInterval?: number = 0,
7779
}
7880
```
7981

@@ -86,6 +88,8 @@ type Config = {
8688

8789
`withExtraHeadRequest`: flag that denotes whether the extra ping check will be performed or not. Defaults to `true`.
8890

91+
`checkConnectionInterval`: the interval (in ms) you want to ping the server at. The default is 0, and that means it is not going to regularly check connectivity.
92+
8993
##### Usage
9094
```js
9195
import React from 'react';
@@ -198,7 +202,7 @@ let App = () => (
198202

199203
App = withNetworkConnectivity({
200204
withRedux: true // It won't inject isConnected as a prop in this case
201-
})(App);
205+
})(App);
202206

203207
const Root = () => (
204208
<Provider store={store}>
@@ -225,7 +229,7 @@ createNetworkMiddleware(config: Config): ReduxMiddleware
225229

226230
type Config = {
227231
regexActionType?: RegExp = /FETCH.*REQUEST/,
228-
actionTypes?: Array<string> = []
232+
actionTypes?: Array<string> = []
229233
}
230234
```
231235

@@ -257,7 +261,7 @@ export const fetchUser = (url) => {
257261
console.error(error);
258262
});
259263
};
260-
264+
261265
thunk.interceptInOffline = true; // This is the important part
262266
return thunk; // Return it afterwards
263267
};
@@ -453,7 +457,7 @@ export default function configureStore(callback) {
453457
});
454458
},
455459
);
456-
460+
457461
return store;
458462
}
459463
```
@@ -475,10 +479,10 @@ class App extends Component {
475479
store: configureStore(() => this.setState({ isLoading: false })),
476480
};
477481
}
478-
482+
479483
render() {
480484
if (this.state.isLoading) return null;
481-
485+
482486
return (
483487
<Provider store={this.state.store}>
484488
<Root />
@@ -522,4 +526,3 @@ Thanks to Spencer Carli for his awesome article about [Handling Offline actions
522526
523527
### License
524528
MIT
525-

src/checkConnectivityInterval.js

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// @flow
2+
3+
let interval = null;
4+
5+
export const setupConnectivityCheckInterval = (
6+
connectivityCheck: Function,
7+
checkConnectionInterval: number,
8+
) => {
9+
if (checkConnectionInterval && !interval) {
10+
interval = setInterval(connectivityCheck, checkConnectionInterval);
11+
}
12+
};
13+
14+
export const clearConnectivityCheckInterval = () => {
15+
if (interval) {
16+
clearInterval(interval);
17+
}
18+
};

src/checkInternetAccess.js

-5
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,9 @@
11
/* @flow */
22

33
export default function checkInternetAccess(
4-
isConnected: boolean,
54
timeout: number = 3000,
65
address: string = 'https://google.com',
76
): Promise<boolean> {
8-
if (!isConnected) {
9-
return Promise.resolve(false);
10-
}
11-
127
return new Promise((resolve: (value: boolean) => void) => {
138
const tm = setTimeout(() => {
149
resolve(false);

src/withNetworkConnectivity.js

+32-12
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ import hoistStatics from 'hoist-non-react-statics';
77
import { connectionChange } from './actionCreators';
88
import reactConnectionStore from './reactConnectionStore';
99
import checkInternetAccess from './checkInternetAccess';
10+
import {
11+
setupConnectivityCheckInterval,
12+
clearConnectivityCheckInterval,
13+
} from './checkConnectivityInterval';
1014

1115
type Arguments = {
1216
withRedux?: boolean,
@@ -25,6 +29,7 @@ const withNetworkConnectivity = (
2529
timeout = 3000,
2630
pingServerUrl = 'https://google.com',
2731
withExtraHeadRequest = true,
32+
checkConnectionInterval = 0,
2833
}: Arguments = {},
2934
) => (WrappedComponent: ReactClass<*>) => {
3035
if (typeof withRedux !== 'boolean') {
@@ -55,32 +60,43 @@ const withNetworkConnectivity = (
5560
'connectionChange',
5661
withExtraHeadRequest
5762
? this.checkInternet
58-
: this.handleConnectivityChange,
63+
: this.handleNetInfoChange,
5964
);
65+
6066
// On Android the listener does not fire on startup
6167
if (Platform.OS === 'android') {
62-
NetInfo.isConnected.fetch().then((isConnected: boolean) => {
63-
if (withExtraHeadRequest) {
64-
this.checkInternet(isConnected);
65-
} else {
66-
this.handleConnectivityChange(isConnected);
67-
}
68-
});
68+
NetInfo.isConnected.fetch().then(withExtraHeadRequest
69+
? this.handleNetInfoChange
70+
: this.handleConnectivityChange
71+
);
6972
}
73+
74+
setupConnectivityCheckInterval(
75+
this.checkInternet,
76+
checkConnectionInterval,
77+
);
7078
}
7179

7280
componentWillUnmount() {
7381
NetInfo.isConnected.removeEventListener(
7482
'connectionChange',
7583
withExtraHeadRequest
76-
? this.checkInternet
84+
? this.handleNetInfoChange
7785
: this.handleConnectivityChange,
7886
);
87+
clearConnectivityCheckInterval();
7988
}
8089

81-
checkInternet = (isConnected: boolean) => {
90+
handleNetInfoChange = (isConnected: boolean) => {
91+
if (!isConnected) {
92+
this.handleConnectivityChange(isConnected);
93+
} else {
94+
this.checkInternet();
95+
}
96+
};
97+
98+
checkInternet = () => {
8299
checkInternetAccess(
83-
isConnected,
84100
timeout,
85101
pingServerUrl,
86102
).then((hasInternetAccess: boolean) => {
@@ -91,14 +107,18 @@ const withNetworkConnectivity = (
91107
handleConnectivityChange = (isConnected: boolean) => {
92108
const { store } = this.context;
93109
reactConnectionStore.setConnection(isConnected);
110+
94111
// Top most component, syncing with store
95112
if (
96113
typeof store === 'object' &&
97114
typeof store.dispatch === 'function' &&
98115
withRedux === true
99116
) {
100117
const actionQueue = store.getState().network.actionQueue;
101-
store.dispatch(connectionChange(isConnected));
118+
119+
if (isConnected !== store.getState().network.isConnected) {
120+
store.dispatch(connectionChange(isConnected));
121+
}
102122
// dispatching queued actions in order of arrival (if we have any)
103123
if (isConnected && actionQueue.length > 0) {
104124
actionQueue.forEach((action: *) => {

0 commit comments

Comments
 (0)