Skip to content

Commit

Permalink
feat: refactor the useNetwork hook.
Browse files Browse the repository at this point in the history
Improved hook performance, now works with safari.

BREAKING CHANGE: `useNetwork` hook renamed to `useNetworkState`.
  • Loading branch information
xobotyi committed Jan 31, 2021
1 parent 723c588 commit 23037f2
Show file tree
Hide file tree
Showing 9 changed files with 238 additions and 126 deletions.
4 changes: 2 additions & 2 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ ij_typescript_catch_on_new_line = false
ij_typescript_spaces_within_interpolation_expressions = false

[*.md]
max_line_length = 0
max_line_length = 120
trim_trailing_whitespace = false

[COMMIT_EDITMSG]
max_line_length = 0
max_line_length = 80
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
- [`useMotion`](./docs/useMotion.md) — tracks state of device's motion sensor.
- [`useMouse` and `useMouseHovered`](./docs/useMouse.md) — tracks state of mouse position. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/sensors-usemouse--docs)
- [`useMouseWheel`](./docs/useMouseWheel.md) — tracks deltaY of scrolled mouse wheel. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/sensors-usemousewheel--docs)
- [`useNetwork`](./docs/useNetwork.md) — tracks state of user's internet connection.
- [`useNetworkState`](./docs/useNetworkState.md) — tracks the state of browser's network connection. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/sensors-usenetworkstate--demo)
- [`useOrientation`](./docs/useOrientation.md) — tracks state of device's screen orientation.
- [`usePageLeave`](./docs/usePageLeave.md) — triggers when mouse leaves page boundaries.
- [`useScratch`](./docs/useScratch.md) — tracks mouse click-and-scrub state.
Expand Down
29 changes: 0 additions & 29 deletions docs/useNetwork.md

This file was deleted.

77 changes: 77 additions & 0 deletions docs/useNetworkState.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# `useNetworkState`

Tracks the state of browser's network connection.

As of the standard it is not guaranteed that browser connected to the _Internet_, it only guarantees the network
connection.

## Usage

```jsx
import {useNetworkState} from 'react-use';

const Demo = () => {
const state = useNetworkState();

return (
<pre>
{JSON.stringify(state, null, 2)}
</pre>
);
};
```

#### State interface:

```typescript
interface IUseNetworkState {
/**
* @desc Whether browser connected to the network or not.
*/
online: boolean | undefined;
/**
* @desc Previous value of `online` property. Helps to identify if browser
* just connected or lost connection.
*/
previous: boolean | undefined;
/**
* @desc The {Date} object pointing to the moment when state change occurred.
*/
since: Date | undefined;
/**
* @desc Effective bandwidth estimate in megabits per second, rounded to the
* nearest multiple of 25 kilobits per seconds.
*/
downlink: number | undefined;
/**
* @desc Maximum downlink speed, in megabits per second (Mbps), for the
* underlying connection technology
*/
downlinkMax: number | undefined;
/**
* @desc Effective type of the connection meaning one of 'slow-2g', '2g', '3g', or '4g'.
* This value is determined using a combination of recently observed round-trip time
* and downlink values.
*/
effectiveType: 'slow-2g' | '2g' | '3g' | '4g' | undefined;
/**
* @desc Estimated effective round-trip time of the current connection, rounded
* to the nearest multiple of 25 milliseconds
*/
rtt: number | undefined;
/**
* @desc Wheter user has set a reduced data usage option on the user agent.
*/
saveData: boolen | undefined;
/**
* @desc The type of connection a device is using to communicate with the network.
*/
type: 'bluetooth' | 'cellular' | 'ethernet' | 'none' | 'wifi' | 'wimax' | 'other' | 'unknown' | undefined;
}
```

#### Call signature

```typescript
function useNetworkState(initialState?: IUseNetworkState | (() => IUseNetworkState)): IUseNetworkState;
```
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export { default as useMountedState } from './useMountedState';
export { default as useMouse } from './useMouse';
export { default as useMouseHovered } from './useMouseHovered';
export { default as useMouseWheel } from './useMouseWheel';
export { default as useNetwork } from './useNetwork';
export { default as useNetworkState } from './useNetworkState';
export { default as useNumber } from './useNumber';
export { default as useObservable } from './useObservable';
export { default as useOrientation } from './useOrientation';
Expand Down
88 changes: 0 additions & 88 deletions src/useNetwork.ts

This file was deleted.

118 changes: 118 additions & 0 deletions src/useNetworkState.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import { useEffect, useState } from 'react';
import { off, on } from './misc/util';
import { IHookStateInitAction } from './misc/hookState';

export interface INetworkInformation extends EventTarget {
readonly downlink: number;
readonly downlinkMax: number;
readonly effectiveType: 'slow-2g' | '2g' | '3g' | '4g';
readonly rtt: number;
readonly saveData: boolean;
readonly type: 'bluetooth' | 'cellular' | 'ethernet' | 'none' | 'wifi' | 'wimax' | 'other' | 'unknown';

onChange: (event: Event) => void;
}

export interface IUseNetworkState {
/**
* @desc Whether browser connected to the network or not.
*/
online: boolean | undefined;
/**
* @desc Previous value of `online` property. Helps to identify if browser
* just connected or lost connection.
*/
previous: boolean | undefined;
/**
* @desc The {Date} object pointing to the moment when state change occurred.
*/
since: Date | undefined;
/**
* @desc Effective bandwidth estimate in megabits per second, rounded to the
* nearest multiple of 25 kilobits per seconds.
*/
downlink: INetworkInformation['downlink'] | undefined;
/**
* @desc Maximum downlink speed, in megabits per second (Mbps), for the
* underlying connection technology
*/
downlinkMax: INetworkInformation['downlinkMax'] | undefined;
/**
* @desc Effective type of the connection meaning one of 'slow-2g', '2g', '3g', or '4g'.
* This value is determined using a combination of recently observed round-trip time
* and downlink values.
*/
effectiveType: INetworkInformation['effectiveType'] | undefined;
/**
* @desc Estimated effective round-trip time of the current connection, rounded
* to the nearest multiple of 25 milliseconds
*/
rtt: INetworkInformation['rtt'] | undefined;
/**
* @desc {true} if the user has set a reduced data usage option on the user agent.
*/
saveData: INetworkInformation['saveData'] | undefined;
/**
* @desc The type of connection a device is using to communicate with the network.
* It will be one of the following values:
* - bluetooth
* - cellular
* - ethernet
* - none
* - wifi
* - wimax
* - other
* - unknown
*/
type: INetworkInformation['type'] | undefined;
}

const nav:
| (Navigator & Partial<Record<'connection' | 'mozConnection' | 'webkitConnection', INetworkInformation>>)
| undefined = navigator;
const conn: INetworkInformation | undefined = nav && (nav.connection || nav.mozConnection || nav.webkitConnection);

function getConnectionState(previousState?: IUseNetworkState): IUseNetworkState {
const online = nav?.onLine;
const previousOnline = previousState?.online;

return {
online,
previous: previousOnline,
since: online !== previousOnline ? new Date() : previousState?.since,
downlink: conn?.downlink,
downlinkMax: conn?.downlinkMax,
effectiveType: conn?.effectiveType,
rtt: conn?.rtt,
saveData: conn?.saveData,
type: conn?.type,
};
}

export default function useNetworkState(initialState?: IHookStateInitAction<IUseNetworkState>): IUseNetworkState {
const [state, setState] = useState(initialState ?? getConnectionState);

useEffect(() => {
const handleStateChange = () => {
setState(getConnectionState);
};

on(window, 'online', handleStateChange, { passive: true });
on(window, 'offline', handleStateChange, { passive: true });

if (conn) {
on(conn, 'change', handleStateChange, { passive: true });
}

return () => {
off(window, 'online', handleStateChange);
off(window, 'offline', handleStateChange);

if (conn) {
off(conn, 'change', handleStateChange);
}
};
}, []);

return state;
}
18 changes: 13 additions & 5 deletions stories/useNetwork.story.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
import { storiesOf } from '@storybook/react';
import * as React from 'react';
import { useNetwork } from '../src';
import { useEffect } from 'react';
import { useNetworkState } from '../src';
import ShowDocs from './util/ShowDocs';

const Demo = () => {
const state = useNetwork();
const state = useNetworkState();

return <pre>{JSON.stringify(state, null, 2)}</pre>;
useEffect(() => {
console.log(state);
}, [state])

return <div>
<div>Since JSON do not output `undefined` fields look the console to see whole the state</div>
<pre>{JSON.stringify(state, null, 2)}</pre>
</div>;
};

storiesOf('Sensors/useNetwork', module)
.add('Docs', () => <ShowDocs md={require('../docs/useNetwork.md')} />)
storiesOf('Sensors/useNetworkState', module)
.add('Docs', () => <ShowDocs md={require('../docs/useNetworkState.md')} />)
.add('Demo', () => <Demo />);
26 changes: 26 additions & 0 deletions tests/useNetworkState.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { renderHook } from '@testing-library/react-hooks';
import { useNetworkState } from '../src';

//ToDo: improve tests
describe(`useNetworkState`, () => {
it('should be defined', () => {
expect(useNetworkState).toBeDefined();
});

it('should return an object of certain structure', () => {
const hook = renderHook(() => useNetworkState(), { initialProps: false });

expect(typeof hook.result.current).toEqual('object');
expect(Object.keys(hook.result.current)).toEqual([
'online',
'previous',
'since',
'downlink',
'downlinkMax',
'effectiveType',
'rtt',
'saveData',
'type',
]);
});
});

0 comments on commit 23037f2

Please sign in to comment.