diff --git a/docs/useBattery.md b/docs/useBattery.md
index 4ddbcc1e..69f0403c 100644
--- a/docs/useBattery.md
+++ b/docs/useBattery.md
@@ -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,34 @@ React sensor hook that tracks battery status.
import {useBattery} from 'react-use';
const Demo = () => {
- const state = useBattery();
+ const batteryState = useBattery();
+ if (!batteryState.isSupported) {
+ return (
+
+
Battery sensor:
not supported
+
+ );
+ }
return (
-
- {JSON.stringify(state, null, 2)}
-
+
+ Battery sensor: supported
+ Charge level: {(batteryState.level * 100).toFixed(0)}%
+ Charging: {batteryState.charging ? 'yes' : 'no'}
+ Charging time: {batteryState.chargingTime ? batteryState.chargingTime : 'finished'}
+ Discharging time: {batteryState.dischargingTime}
+
);
};
```
+
+## Reference
+
+```ts
+const {isSupported, level, charging, dischargingTime, chargingTime} = useBattery();
+```
+- **`isSupported`**_`: boolean`_ - wheter browser/devise supports BatteryManager;
+- **`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.
diff --git a/src/__stories__/useBattery.story.tsx b/src/__stories__/useBattery.story.tsx
index 5c6ae635..922b1442 100644
--- a/src/__stories__/useBattery.story.tsx
+++ b/src/__stories__/useBattery.story.tsx
@@ -4,9 +4,29 @@ import { useBattery } from '..';
import ShowDocs from './util/ShowDocs';
const Demo = () => {
- const state = useBattery();
+ const batteryState = useBattery();
- return {JSON.stringify(state, null, 2)};
+ if (!batteryState.isSupported) {
+ return (
+
+
Battery sensor:
not supported
+
+ );
+ }
+ return (
+
+ Battery sensor: supported
+
+ Charge level: {(batteryState.level * 100).toFixed(0)}%
+
+ Charging: {batteryState.charging ? 'yes' : 'no'}
+
+ Charging time:
+ {batteryState.chargingTime ? batteryState.chargingTime : 'finished'}
+
+ Discharging time: {batteryState.dischargingTime}
+
+ );
};
storiesOf('Sensors|useBattery', module)
diff --git a/src/useBattery.ts b/src/useBattery.ts
index a5cfd5c2..fdba50ca 100644
--- a/src/useBattery.ts
+++ b/src/useBattery.ts
@@ -1,56 +1,106 @@
-import { useEffect, useState } from 'react';
+import * as React from 'react';
import { off, on } from './util';
-export interface BatterySensorState {
- charging: boolean;
- level: number;
- chargingTime: number;
- dischargingTime: number;
+enum BatteryManagerEvents {
+ levelChange = 'levelchange',
+ dischargingTimeChange = 'dischargingtimechange',
+ chargingTimeChange = 'chargingtimechange',
+ chargingChange = 'chargingchange',
}
-const useBattery = () => {
- const [state, setState] = useState({});
- let mounted = true;
- let battery: any = null;
+export interface BatteryState {
+ charging: boolean;
+ chargingTime: number;
+ dischargingTime: number;
+ level: number;
+}
- const onChange = () => {
- const { charging, level, chargingTime, dischargingTime } = battery;
- setState({
- charging,
- level,
- chargingTime,
- dischargingTime,
- });
- };
+interface BatteryManager extends Readonly, EventTarget {
+ onchargingchange: () => void;
+ onchargingtimechange: () => void;
+ ondischargingtimechange: () => void;
+ onlevelchange: () => void;
+}
- const onBattery = () => {
- onChange();
- on(battery, 'chargingchange', onChange);
- on(battery, 'levelchange', onChange);
- on(battery, 'chargingtimechange', onChange);
- on(battery, 'dischargingtimechange', onChange);
- };
+interface NavigatorWithPossibleBattery extends Navigator {
+ getBattery?: () => Promise;
+}
- useEffect(() => {
- (navigator as any).getBattery().then((bat: any) => {
- if (mounted) {
- battery = bat;
- onBattery();
- }
- });
+const nav: NavigatorWithPossibleBattery = navigator;
- return () => {
- mounted = false;
- if (battery) {
- off(battery, 'chargingchange', onChange);
- off(battery, 'levelchange', onChange);
- off(battery, 'chargingtimechange', onChange);
- off(battery, 'dischargingtimechange', onChange);
- }
- };
- }, []);
-
- return state;
+type UseBatteryState = BatteryState & {
+ isSupported: boolean;
};
-export default useBattery;
+export default function useBattery() {
+ const [state, setState] = React.useState({
+ isSupported: nav && typeof nav.getBattery !== 'undefined',
+ level: 1,
+ charging: true,
+ dischargingTime: Infinity,
+ chargingTime: 0,
+ });
+ const battery = React.useRef();
+ let isMounted = true;
+
+ if (state.isSupported) {
+ const onChange = React.useCallback(() => {
+ if (isMounted && battery.current) {
+ setState({
+ isSupported: true,
+ level: battery.current.level,
+ charging: battery.current.charging,
+ dischargingTime: battery.current.dischargingTime,
+ chargingTime: battery.current.chargingTime,
+ });
+ }
+ }, [setState]);
+
+ const bindBatteryEvents = React.useCallback(
+ (bat: BatteryManager) => {
+ on(bat, BatteryManagerEvents.chargingChange, onChange);
+ on(bat, BatteryManagerEvents.chargingTimeChange, onChange);
+ on(bat, BatteryManagerEvents.dischargingTimeChange, onChange);
+ on(bat, BatteryManagerEvents.levelChange, onChange);
+ },
+ [onChange]
+ );
+
+ const unbindBatteryEvents = React.useCallback(
+ (bat: BatteryManager) => {
+ off(bat, BatteryManagerEvents.chargingChange, onChange);
+ off(bat, BatteryManagerEvents.chargingTimeChange, onChange);
+ off(bat, BatteryManagerEvents.dischargingTimeChange, onChange);
+ off(bat, BatteryManagerEvents.levelChange, onChange);
+ },
+ [onChange]
+ );
+
+ React.useEffect(() => {
+ battery.current && bindBatteryEvents(battery.current);
+
+ return () => {
+ battery.current && unbindBatteryEvents(battery.current);
+ };
+ }, [onChange]);
+
+ React.useEffect(() => {
+ nav.getBattery!().then((bat: BatteryManager) => {
+ if (!isMounted) {
+ return;
+ }
+
+ battery.current = bat;
+ bindBatteryEvents(bat);
+ });
+
+ return () => {
+ isMounted = false;
+
+ battery.current && unbindBatteryEvents(battery.current);
+ };
+ }, []);
+ }
+
+ return state;
+}