mirror of
https://github.com/zhigang1992/react-native-web.git
synced 2026-03-26 09:14:15 +08:00
[fix] latest NetInfo API
Update the NetInfo API to conform to the latest React Native implementation. Web-only properties are also included now. Fix #662 Close #663
This commit is contained in:
committed by
Nicolas Gallagher
parent
0d29458874
commit
6ef19c3ccd
@@ -1,9 +1,19 @@
|
||||
# NetInfo
|
||||
|
||||
`NetInfo` asynchronously determines the online/offline status of the
|
||||
application.
|
||||
application and depending on browser support via
|
||||
[NetworkInformation API](https://developer.mozilla.org/en-US/docs/Web/API/NetworkInformation),
|
||||
additional information about the connection.
|
||||
|
||||
Connection types:
|
||||
EffectiveConnectionType:
|
||||
|
||||
* `4g`
|
||||
* `3g`
|
||||
* `2g`
|
||||
* `slow-2g`
|
||||
* `unknown`
|
||||
|
||||
ConnectionType:
|
||||
|
||||
* `bluetooth` - The user agent is using a Bluetooth connection.
|
||||
* `cellular` - The user agent is using a cellular connection (e.g., EDGE, HSPA, LTE, etc.).
|
||||
@@ -18,12 +28,12 @@ Connection types:
|
||||
## Methods
|
||||
|
||||
Note that support for retrieving the connection type depends upon browswer
|
||||
support (and is limited to mobile browsers). It will default to `unknown` when
|
||||
support and the current platform. It will default to `unknown` when
|
||||
support is missing.
|
||||
|
||||
static **addEventListener**(eventName: ChangeEventName, handler: Function)
|
||||
|
||||
static **fetch**(): Promise
|
||||
static **getConnectionInfo**(): Promise
|
||||
|
||||
static **removeEventListener**(eventName: ChangeEventName, handler: Function)
|
||||
|
||||
@@ -36,7 +46,7 @@ internet connectivity. Use this if you are only interested with whether the devi
|
||||
|
||||
**isConnected.addEventListener**(eventName: ChangeEventName, handler: Function)
|
||||
|
||||
**isConnected.fetch**(): Promise
|
||||
**isConnected.getConnectionInfo**(): Promise
|
||||
|
||||
**isConnected.removeEventListener**(eventName: ChangeEventName, handler: Function)
|
||||
|
||||
@@ -45,24 +55,25 @@ internet connectivity. Use this if you are only interested with whether the devi
|
||||
Fetching the connection type:
|
||||
|
||||
```js
|
||||
NetInfo.fetch().then((connectionType) => {
|
||||
console.log('Connection type:', connectionType);
|
||||
NetInfo.getConnectionInfo().then(({ effectiveType, type }) => {
|
||||
console.log('Effective connection type:', effectiveType);
|
||||
console.log('Connection type:', type);
|
||||
});
|
||||
```
|
||||
|
||||
Subscribing to changes in the connection type:
|
||||
|
||||
```js
|
||||
const handleConnectivityTypeChange = (connectionType) => {
|
||||
console.log('Current connection type:', connectionType);
|
||||
const handleConnectivityTypeChange = ({ effectiveType }) => {
|
||||
console.log('Current effective connection type:', effectiveType);
|
||||
}
|
||||
NetInfo.addEventListener('change', handleConnectivityTypeChange);
|
||||
NetInfo.addEventListener('connectionChange', handleConnectivityTypeChange);
|
||||
```
|
||||
|
||||
Fetching the connection status:
|
||||
|
||||
```js
|
||||
NetInfo.isConnected.fetch().then((isConnected) => {
|
||||
NetInfo.isConnected.getConnectionInfo().then((isConnected) => {
|
||||
console.log('Connection status:', (isConnected ? 'online' : 'offline'));
|
||||
});
|
||||
```
|
||||
@@ -73,5 +84,5 @@ Subscribing to changes in the connection status:
|
||||
const handleConnectivityStatusChange = (isConnected) => {
|
||||
console.log('Current connection status:', (isConnected ? 'online' : 'offline'));
|
||||
}
|
||||
NetInfo.isConnected.addEventListener('change', handleConnectivityStatusChange);
|
||||
NetInfo.isConnected.addEventListener('connectionChange', handleConnectivityStatusChange);
|
||||
```
|
||||
|
||||
@@ -8,61 +8,94 @@ import UIExplorer, {
|
||||
Code,
|
||||
Description,
|
||||
DocItem,
|
||||
ExternalLink,
|
||||
Section,
|
||||
storiesOf,
|
||||
TextList
|
||||
storiesOf
|
||||
} from '../../ui-explorer';
|
||||
|
||||
const NetInfoScreen = () => (
|
||||
<UIExplorer title="NetInfo" url="2-apis/NetInfo">
|
||||
<Description>
|
||||
<AppText>
|
||||
NetInfo asynchronously determines the online/offline status of the application.
|
||||
NetInfo asynchronously determines the online/offline status and additional connection
|
||||
information (where available) of the application.
|
||||
</AppText>
|
||||
<AppText>
|
||||
Note that support for retrieving the connection type depends upon browser support (and is
|
||||
limited to mobile browsers). It will default to <Code>unknown</Code> when support is
|
||||
missing.
|
||||
Note that connection type information is limited to how well the browser supports the{' '}
|
||||
<ExternalLink href="https://developer.mozilla.org/en-US/docs/Web/API/NetworkInformation">
|
||||
NetworkInformation API
|
||||
</ExternalLink>. Connection types will be <Code>unknown</Code> when support is missing.
|
||||
</AppText>
|
||||
</Description>
|
||||
|
||||
<Section title="Types">
|
||||
<DocItem
|
||||
description={
|
||||
<AppText>
|
||||
One of <Code>slow-2g</Code>, <Code>2g</Code>, <Code>3g</Code>, <Code>4g</Code>,{' '}
|
||||
<Code>unknown</Code>.
|
||||
</AppText>
|
||||
}
|
||||
name="ConnectionType"
|
||||
/>
|
||||
<DocItem
|
||||
description={
|
||||
<AppText>
|
||||
One of <Code>bluebooth</Code>, <Code>cellular</Code>, <Code>ethernet</Code>,{' '}
|
||||
<Code>mixed</Code>, <Code>mixed</Code>, <Code>none</Code>, <Code>other</Code>,{' '}
|
||||
<Code>unknown</Code>, <Code>wifi</Code>, <Code>wimax</Code>
|
||||
</AppText>
|
||||
}
|
||||
name="EffectiveConnectionType"
|
||||
/>
|
||||
|
||||
<DocItem
|
||||
description={
|
||||
<Code>{`{
|
||||
effectiveType: EffectiveConnectionType;
|
||||
type: ConnectionType;
|
||||
downlink?: number;
|
||||
downlinkMax?: number;
|
||||
rtt?: number;
|
||||
}`}</Code>
|
||||
}
|
||||
name="ConnectionEventType"
|
||||
/>
|
||||
</Section>
|
||||
|
||||
<Section title="Methods">
|
||||
<DocItem
|
||||
description={[
|
||||
description={
|
||||
<AppText>
|
||||
Invokes the listener whenever network status changes. The listener receives one of the
|
||||
following connectivity types (from the DOM connection API):
|
||||
</AppText>,
|
||||
<TextList
|
||||
items={[
|
||||
'bluetooth',
|
||||
'cellular',
|
||||
'ethernet',
|
||||
'mixed',
|
||||
'none',
|
||||
'other',
|
||||
'unknown',
|
||||
'wifi',
|
||||
'wimax'
|
||||
]}
|
||||
/>
|
||||
]}
|
||||
Adds an event handler. The <Code>connectionChange</Code> event fires when the network
|
||||
status changes. The argument to the event handler is an object of type{' '}
|
||||
<Code>ConnectionEventType</Code>.
|
||||
</AppText>
|
||||
}
|
||||
example={{
|
||||
code: "NetInfo.addEventListener('change', (connectionType) => {})"
|
||||
code: `NetInfo.addEventListener('connectionChange', ({ effectiveType, type }) => {
|
||||
console.log('Effective connection type:', effectiveType);
|
||||
console.log('Connection type:', type);
|
||||
})`
|
||||
}}
|
||||
name="static addEventListener"
|
||||
typeInfo="(eventName, handler) => void"
|
||||
/>
|
||||
|
||||
<DocItem
|
||||
description="Returns a promise that resolves with one of the connectivity types listed above."
|
||||
description={
|
||||
<AppText>
|
||||
Returns a promise that resolves with an object of type <Code>ConnectionEventType</Code>.
|
||||
</AppText>
|
||||
}
|
||||
example={{
|
||||
code: `NetInfo.fetch().then((connectionType) => {
|
||||
console.log('Connection type:', connectionType);
|
||||
code: `NetInfo.getConnectionInfo().then(({ effectiveType, type }) => {
|
||||
console.log('Effective connection type:', effectiveType);
|
||||
console.log('Connection type:', type);
|
||||
});`
|
||||
}}
|
||||
name="static fetch"
|
||||
typeInfo="() => Promise<string>"
|
||||
name="static getConnectionInfo"
|
||||
typeInfo="() => Promise<ConnectionEventType>"
|
||||
/>
|
||||
|
||||
<DocItem
|
||||
@@ -76,7 +109,7 @@ const NetInfoScreen = () => (
|
||||
<DocItem
|
||||
description="An object with the same methods as above but the listener receives a boolean which represents the internet connectivity. Use this if you are only interested with whether the device has internet connectivity."
|
||||
example={{
|
||||
code: `NetInfo.isConnected.fetch().then((isConnected) => {
|
||||
code: `NetInfo.isConnected.getConnectionInfo().then((isConnected) => {
|
||||
console.log('Connection status:', (isConnected ? 'online' : 'offline'));
|
||||
});`
|
||||
}}
|
||||
|
||||
@@ -3,31 +3,44 @@
|
||||
import NetInfo from '..';
|
||||
|
||||
describe('apis/NetInfo', () => {
|
||||
describe('getConnectionInfo', () => {
|
||||
test('fills out basic fields', done => {
|
||||
NetInfo.getConnectionInfo().then(result => {
|
||||
expect(result.effectiveType).toBeDefined();
|
||||
expect(result.type).toBeDefined();
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('isConnected', () => {
|
||||
const handler = () => {};
|
||||
|
||||
afterEach(() => {
|
||||
try {
|
||||
NetInfo.isConnected.removeEventListener('change', handler);
|
||||
NetInfo.isConnected.removeEventListener('connectionChange', handler);
|
||||
} catch (e) {}
|
||||
});
|
||||
|
||||
describe('addEventListener', () => {
|
||||
test('throws if the provided "eventType" is not supported', () => {
|
||||
expect(() => NetInfo.isConnected.addEventListener('foo', handler)).toThrow();
|
||||
expect(() => NetInfo.isConnected.addEventListener('change', handler)).not.toThrow();
|
||||
expect(() =>
|
||||
NetInfo.isConnected.addEventListener('connectionChange', handler)
|
||||
).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('removeEventListener', () => {
|
||||
test('throws if the handler is not registered', () => {
|
||||
expect(() => NetInfo.isConnected.removeEventListener('change', handler)).toThrow;
|
||||
expect(() => NetInfo.isConnected.removeEventListener('connectionChange', handler)).toThrow;
|
||||
});
|
||||
|
||||
test('throws if the provided "eventType" is not supported', () => {
|
||||
NetInfo.isConnected.addEventListener('change', handler);
|
||||
NetInfo.isConnected.addEventListener('connectionChange', handler);
|
||||
expect(() => NetInfo.isConnected.removeEventListener('foo', handler)).toThrow;
|
||||
expect(() => NetInfo.isConnected.removeEventListener('change', handler)).not.toThrow;
|
||||
expect(() => NetInfo.isConnected.removeEventListener('connectionChange', handler)).not
|
||||
.toThrow;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -20,7 +20,27 @@ const connection =
|
||||
window.navigator.mozConnection ||
|
||||
window.navigator.webkitConnection);
|
||||
|
||||
const eventTypes = ['change'];
|
||||
// Prevent the underlying event handlers from leaking and include additional
|
||||
// properties available in browsers
|
||||
const getConnectionInfoObject = () => {
|
||||
const result = {};
|
||||
if (!connection) {
|
||||
return result;
|
||||
}
|
||||
for (const prop in connection) {
|
||||
if (typeof connection[prop] !== 'function') {
|
||||
result[prop] = connection[prop];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
// Map React Native events to browser equivalents
|
||||
const eventTypesMap = {
|
||||
change: 'change',
|
||||
connectionChange: 'change'
|
||||
};
|
||||
const eventTypes = Object.keys(eventTypesMap);
|
||||
|
||||
const connectionListeners = [];
|
||||
|
||||
@@ -31,6 +51,9 @@ const connectionListeners = [];
|
||||
const NetInfo = {
|
||||
addEventListener(type: string, handler: Function): { remove: () => void } {
|
||||
invariant(eventTypes.indexOf(type) !== -1, 'Trying to subscribe to unknown event: "%s"', type);
|
||||
if (type === 'change') {
|
||||
console.warn('Listening to event `change` is deprecated. Use `connectionChange` instead.');
|
||||
}
|
||||
if (!connection) {
|
||||
console.error(
|
||||
'Network Connection API is not supported. Not listening for connection type changes.'
|
||||
@@ -40,21 +63,25 @@ const NetInfo = {
|
||||
};
|
||||
}
|
||||
|
||||
connection.addEventListener(type, handler);
|
||||
connection.addEventListener(eventTypesMap[type], handler);
|
||||
return {
|
||||
remove: () => NetInfo.removeEventListener(type, handler)
|
||||
remove: () => NetInfo.removeEventListener(eventTypesMap[type], handler)
|
||||
};
|
||||
},
|
||||
|
||||
removeEventListener(type: string, handler: Function): void {
|
||||
invariant(eventTypes.indexOf(type) !== -1, 'Trying to subscribe to unknown event: "%s"', type);
|
||||
if (type === 'change') {
|
||||
console.warn('Listening to event `change` is deprecated. Use `connectionChange` instead.');
|
||||
}
|
||||
if (!connection) {
|
||||
return;
|
||||
}
|
||||
connection.removeEventListener(type, handler);
|
||||
connection.removeEventListener(eventTypesMap[type], handler);
|
||||
},
|
||||
|
||||
fetch(): Promise<any> {
|
||||
console.warn('`fetch` is deprecated. Use `getConnectionInfo` instead.');
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
resolve(connection.type);
|
||||
@@ -64,6 +91,16 @@ const NetInfo = {
|
||||
});
|
||||
},
|
||||
|
||||
getConnectionInfo(): Promise<Object> {
|
||||
return new Promise((resolve, reject) => {
|
||||
resolve({
|
||||
effectiveType: 'unknown',
|
||||
type: 'unknown',
|
||||
...getConnectionInfoObject()
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
isConnected: {
|
||||
addEventListener(type: string, handler: Function): { remove: () => void } {
|
||||
invariant(
|
||||
@@ -71,6 +108,10 @@ const NetInfo = {
|
||||
'Trying to subscribe to unknown event: "%s"',
|
||||
type
|
||||
);
|
||||
if (type === 'change') {
|
||||
console.warn('Listening to event `change` is deprecated. Use `connectionChange` instead.');
|
||||
}
|
||||
|
||||
const onlineCallback = () => handler(true);
|
||||
const offlineCallback = () => handler(false);
|
||||
connectionListeners.push([handler, onlineCallback, offlineCallback]);
|
||||
@@ -79,7 +120,7 @@ const NetInfo = {
|
||||
window.addEventListener('offline', offlineCallback, false);
|
||||
|
||||
return {
|
||||
remove: () => NetInfo.isConnected.removeEventListener(type, handler)
|
||||
remove: () => NetInfo.isConnected.removeEventListener(eventTypesMap[type], handler)
|
||||
};
|
||||
},
|
||||
|
||||
@@ -89,6 +130,9 @@ const NetInfo = {
|
||||
'Trying to subscribe to unknown event: "%s"',
|
||||
type
|
||||
);
|
||||
if (type === 'change') {
|
||||
console.warn('Listening to event `change` is deprecated. Use `connectionChange` instead.');
|
||||
}
|
||||
|
||||
const listenerIndex = findIndex(connectionListeners, pair => pair[0] === handler);
|
||||
invariant(
|
||||
@@ -103,7 +147,12 @@ const NetInfo = {
|
||||
connectionListeners.splice(listenerIndex, 1);
|
||||
},
|
||||
|
||||
fetch(): Promise<any> {
|
||||
fetch(): Promise<boolean> {
|
||||
console.warn('`fetch` is deprecated. Use `getConnectionInfo` instead.');
|
||||
return NetInfo.isConnected.getConnectionInfo();
|
||||
},
|
||||
|
||||
getConnectionInfo(): Promise<boolean> {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
resolve(window.navigator.onLine);
|
||||
|
||||
Reference in New Issue
Block a user