mirror of
https://github.com/streamich/react-use.git
synced 2026-01-18 14:06:52 +00:00
fix: Reworked useBattery hook
This commit is contained in:
commit
106906013f
@ -2,6 +2,9 @@
|
||||
|
||||
React sensor hook that tracks battery status.
|
||||
|
||||
>**Note:** current `BatteryManager` API state is obsolete.
|
||||
>Although it may still work in some browsers, its use is discouraged since it could be removed at any time.
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
@ -9,12 +12,47 @@ React sensor hook that tracks battery status.
|
||||
import {useBattery} from 'react-use';
|
||||
|
||||
const Demo = () => {
|
||||
const state = useBattery();
|
||||
const batteryState = useBattery();
|
||||
|
||||
if (!batteryState.isSupported) {
|
||||
return (
|
||||
<div>
|
||||
<strong>Battery sensor</strong>: <span>not supported</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (!batteryState.fetched) {
|
||||
return (
|
||||
<div>
|
||||
<strong>Battery sensor</strong>: <span>supported</span> <br />
|
||||
<strong>Battery state</strong>: <span>fetching</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<pre>
|
||||
{JSON.stringify(state, null, 2)}
|
||||
</pre>
|
||||
<div>
|
||||
<strong>Battery sensor</strong>: <span>supported</span> <br />
|
||||
<strong>Battery state</strong>: <span>fetched</span> <br />
|
||||
<strong>Charge level</strong>: <span>{ (batteryState.level * 100).toFixed(0) }%</span> <br />
|
||||
<strong>Charging</strong>: <span>{ batteryState.charging ? 'yes' : 'no' }</span> <br />
|
||||
<strong>Charging time</strong>:
|
||||
<span>{ batteryState.chargingTime ? batteryState.chargingTime : 'finished' }</span> <br />
|
||||
<strong>Discharging time</strong>: <span>{ batteryState.dischargingTime }</span>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
## Reference
|
||||
|
||||
```ts
|
||||
const {isSupported, level, charging, dischargingTime, chargingTime} = useBattery();
|
||||
```
|
||||
- **`isSupported`**_`: boolean`_ - whether browser/devise supports BatteryManager;
|
||||
- **`fetched`**_`: boolean`_ - whether battery state is fetched;
|
||||
- **`level`**_`: number`_ - representing the system's battery charge level scaled to a value between 0.0 and 1.0.
|
||||
- **`charging`**_`: boolean`_ - indicating whether or not the battery is currently being charged.
|
||||
- **`dischargingTime`**_`: number`_ - remaining time in seconds until the battery is completely discharged and the system will suspend.
|
||||
- **`chargingTime`**_`: number`_ - remaining time in seconds until the battery is fully charged, or 0 if the battery is already fully charged.
|
||||
|
||||
@ -4,9 +4,36 @@ import { useBattery } from '..';
|
||||
import ShowDocs from './util/ShowDocs';
|
||||
|
||||
const Demo = () => {
|
||||
const state = useBattery();
|
||||
const batteryState = useBattery();
|
||||
|
||||
return <pre>{JSON.stringify(state, null, 2)}</pre>;
|
||||
if (!batteryState.isSupported) {
|
||||
return (
|
||||
<div>
|
||||
<strong>Battery sensor</strong>: <span>not supported</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (!batteryState.fetched) {
|
||||
return (
|
||||
<div>
|
||||
<strong>Battery sensor</strong>: <span>supported</span> <br />
|
||||
<strong>Battery state</strong>: <span>fetching</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<strong>Battery sensor</strong>: <span>supported</span> <br />
|
||||
<strong>Battery state</strong>: <span>fetched</span> <br />
|
||||
<strong>Charge level</strong>: <span>{(batteryState.level * 100).toFixed(0)}%</span> <br />
|
||||
<strong>Charging</strong>: <span>{batteryState.charging ? 'yes' : 'no'}</span> <br />
|
||||
<strong>Charging time</strong>:
|
||||
<span>{batteryState.chargingTime ? batteryState.chargingTime : 'finished'}</span> <br />
|
||||
<strong>Discharging time</strong>: <span>{batteryState.dischargingTime}</span>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
storiesOf('Sensors|useBattery', module)
|
||||
|
||||
@ -1,56 +1,85 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import * as React from 'react';
|
||||
import * as isEqual from 'react-fast-compare';
|
||||
import { off, on } from './util';
|
||||
|
||||
export interface BatterySensorState {
|
||||
const { useState, useEffect } = React;
|
||||
|
||||
export interface BatteryState {
|
||||
charging: boolean;
|
||||
level: number;
|
||||
chargingTime: number;
|
||||
dischargingTime: number;
|
||||
level: number;
|
||||
}
|
||||
|
||||
const useBattery = () => {
|
||||
const [state, setState] = useState({});
|
||||
let mounted = true;
|
||||
let battery: any = null;
|
||||
interface BatteryManager extends Readonly<BatteryState>, EventTarget {
|
||||
onchargingchange: () => void;
|
||||
onchargingtimechange: () => void;
|
||||
ondischargingtimechange: () => void;
|
||||
onlevelchange: () => void;
|
||||
}
|
||||
|
||||
const onChange = () => {
|
||||
const { charging, level, chargingTime, dischargingTime } = battery;
|
||||
setState({
|
||||
charging,
|
||||
level,
|
||||
chargingTime,
|
||||
dischargingTime,
|
||||
});
|
||||
};
|
||||
interface NavigatorWithPossibleBattery extends Navigator {
|
||||
getBattery?: () => Promise<BatteryManager>;
|
||||
}
|
||||
|
||||
const onBattery = () => {
|
||||
onChange();
|
||||
on(battery, 'chargingchange', onChange);
|
||||
on(battery, 'levelchange', onChange);
|
||||
on(battery, 'chargingtimechange', onChange);
|
||||
on(battery, 'dischargingtimechange', onChange);
|
||||
};
|
||||
type UseBatteryState =
|
||||
| { isSupported: false } // Battery API is not supported
|
||||
| { isSupported: true; fetched: false } // battery API supported but not fetched yet
|
||||
| BatteryState & { isSupported: true; fetched: true }; // battery API supported and fetched
|
||||
|
||||
const nav: NavigatorWithPossibleBattery | undefined = typeof navigator === 'object' ? navigator : undefined;
|
||||
const isBatteryApiSupported = nav && typeof nav.getBattery === 'function';
|
||||
|
||||
function useBatteryMock(): UseBatteryState {
|
||||
return { isSupported: false };
|
||||
}
|
||||
|
||||
function useBattery(): UseBatteryState {
|
||||
const [state, setState] = useState<UseBatteryState>({ isSupported: true, fetched: false });
|
||||
|
||||
useEffect(() => {
|
||||
(navigator as any).getBattery().then((bat: any) => {
|
||||
if (mounted) {
|
||||
battery = bat;
|
||||
onBattery();
|
||||
let isMounted = true;
|
||||
let battery: BatteryManager | null = null;
|
||||
|
||||
const handleChange = () => {
|
||||
if (!isMounted || !battery) {
|
||||
return;
|
||||
}
|
||||
const newState: UseBatteryState = {
|
||||
isSupported: true,
|
||||
fetched: true,
|
||||
level: battery.level,
|
||||
charging: battery.charging,
|
||||
dischargingTime: battery.dischargingTime,
|
||||
chargingTime: battery.chargingTime,
|
||||
};
|
||||
!isEqual(state, newState) && setState(newState);
|
||||
};
|
||||
|
||||
nav!.getBattery!().then((bat: BatteryManager) => {
|
||||
if (!isMounted) {
|
||||
return;
|
||||
}
|
||||
battery = bat;
|
||||
on(battery, 'chargingchange', handleChange);
|
||||
on(battery, 'chargingtimechange', handleChange);
|
||||
on(battery, 'dischargingtimechange', handleChange);
|
||||
on(battery, 'levelchange', handleChange);
|
||||
handleChange();
|
||||
});
|
||||
|
||||
return () => {
|
||||
mounted = false;
|
||||
isMounted = false;
|
||||
if (battery) {
|
||||
off(battery, 'chargingchange', onChange);
|
||||
off(battery, 'levelchange', onChange);
|
||||
off(battery, 'chargingtimechange', onChange);
|
||||
off(battery, 'dischargingtimechange', onChange);
|
||||
off(battery, 'chargingchange', handleChange);
|
||||
off(battery, 'chargingtimechange', handleChange);
|
||||
off(battery, 'dischargingtimechange', handleChange);
|
||||
off(battery, 'levelchange', handleChange);
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
return state;
|
||||
};
|
||||
}
|
||||
|
||||
export default useBattery;
|
||||
export default isBatteryApiSupported ? useBattery : useBatteryMock;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user