Skip to content

Commit

Permalink
feat: 🎸 use only one useState and one useEffect call
Browse files Browse the repository at this point in the history
  • Loading branch information
streamich committed Aug 20, 2019
1 parent 5d31cf0 commit 2d0fabf
Showing 1 changed file with 36 additions and 55 deletions.
91 changes: 36 additions & 55 deletions src/useBattery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import * as React from 'react';
import * as isEqual from 'react-fast-compare';
import { off, on } from './util';

const { useState, useEffect } = React;

export interface BatteryState {
charging: boolean;
chargingTime: number;
Expand Down Expand Up @@ -33,68 +35,47 @@ function useBatteryMock(): UseBatteryState {
}

function useBattery(): UseBatteryState {
const [state, setState] = React.useState<UseBatteryState>({ isSupported: true, fetched: false });
const battery = React.useRef<BatteryManager | null>();
const isMounted = React.useRef(false);

const handleChange = React.useCallback(() => {
if (!isMounted.current || !battery.current) {
return;
}

const newState: UseBatteryState = {
isSupported: true,
fetched: true,
level: battery.current.level,
charging: battery.current.charging,
dischargingTime: battery.current.dischargingTime,
chargingTime: battery.current.chargingTime,
const [state, setState] = useState<UseBatteryState>({ isSupported: true, fetched: false });

useEffect(() => {
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);
};

!isEqual(state, newState) && setState(newState);
}, [state, setState]);

const bindBatteryEvents = React.useCallback(() => {
if (!battery.current || !isMounted.current) {
return;
}

on(battery.current, 'chargingchange', handleChange);
on(battery.current, 'chargingtimechange', handleChange);
on(battery.current, 'dischargingtimechange', handleChange);
on(battery.current, 'levelchange', handleChange);
}, [handleChange]);
const unbindBatteryEvents = React.useCallback(() => {
if (!battery.current) {
return;
}

off(battery.current, 'chargingchange', handleChange);
off(battery.current, 'chargingtimechange', handleChange);
off(battery.current, 'dischargingtimechange', handleChange);
off(battery.current, 'levelchange', handleChange);
}, [handleChange]);

React.useEffect(() => {
bindBatteryEvents();
handleChange(); // this one is for case when update performed between unbind and bind, extremely rare, but better to handle

return unbindBatteryEvents;
}, [handleChange]);

React.useEffect(() => {
isMounted.current = true;

(navigator as NavigatorWithPossibleBattery).getBattery!().then((bat: BatteryManager) => {
battery.current = bat;

bindBatteryEvents();
if (!isMounted) {
return;
}
battery = bat;
on(battery, 'chargingchange', handleChange);
on(battery, 'chargingtimechange', handleChange);
on(battery, 'dischargingtimechange', handleChange);
on(battery, 'levelchange', handleChange);
handleChange();
});

return () => {
isMounted.current = false;
unbindBatteryEvents();
isMounted = false;
if (battery) {
off(battery, 'chargingchange', handleChange);
off(battery, 'chargingtimechange', handleChange);
off(battery, 'dischargingtimechange', handleChange);
off(battery, 'levelchange', handleChange);
}
};
}, []);

Expand Down

0 comments on commit 2d0fabf

Please sign in to comment.