Browse Source

Debounce filterState change

pull/623/head
philon- 1 year ago
parent
commit
7329a66a2c
  1. 82
      src/components/generic/Filter/FilterControl.tsx

82
src/components/generic/Filter/FilterControl.tsx

@ -11,7 +11,13 @@ import { cn } from "@core/utils/cn.ts";
import { TimeAgo } from "@components/generic/TimeAgo.tsx"; import { TimeAgo } from "@components/generic/TimeAgo.tsx";
import type { FilterState } from "@core/hooks/useFilterNode.ts"; import type { FilterState } from "@core/hooks/useFilterNode.ts";
import { FunnelIcon } from "lucide-react"; import { FunnelIcon } from "lucide-react";
import { type ComponentProps, ReactNode } from "react"; import {
type ComponentProps,
ReactNode,
useEffect,
useRef,
useState,
} from "react";
import { import {
FilterAccordionItem, FilterAccordionItem,
FilterMulti, FilterMulti,
@ -44,6 +50,17 @@ export function FilterControl({
parameters, parameters,
children, children,
}: FilterControlProps) { }: FilterControlProps) {
// Copy of the state that we only use for rendering sliders and their labels directly, rest is debounced
const [localFilterState, setLocalFilterState] = useState(filterState);
const skipNextSync = useRef(false);
useEffect(() => {
if (skipNextSync.current) {
skipNextSync.current = false;
return;
}
setLocalFilterState(filterState);
}, [filterState]);
const handleTextChange = const handleTextChange =
<K extends keyof FilterState>(key: K) => <K extends keyof FilterState>(key: K) =>
(e: React.ChangeEvent<HTMLInputElement>) => { (e: React.ChangeEvent<HTMLInputElement>) => {
@ -54,10 +71,23 @@ export function FilterControl({
}; };
const handleRangeChange = const handleRangeChange =
<K extends keyof FilterState>(key: K) => (value: number[]) => { <K extends keyof FilterState>(key: K) => (value: number[]) => {
setFilterState((prev) => ({ // immediate slider update
setLocalFilterState((prev) => ({
...prev, ...prev,
[key]: value, [key]: value,
})); }));
// debounced write to filterState (table/map render)
debounce(
() => {
skipNextSync.current = true;
setFilterState((prev) => ({
...prev,
[key]: value,
}));
},
250,
)();
}; };
const handleBoolChange = <K extends keyof FilterState>( const handleBoolChange = <K extends keyof FilterState>(
key: K, key: K,
@ -135,16 +165,17 @@ export function FilterControl({
<FilterSlider <FilterSlider
label="Number of hops" label="Number of hops"
filterKey="hopsAway" filterKey="hopsAway"
filterState={filterState} filterState={localFilterState}
defaultFilterValues={defaultFilterValues} defaultFilterValues={defaultFilterValues}
onChange={handleRangeChange} onChange={handleRangeChange}
labelContent={ labelContent={
<> <>
Number of hops: {filterState.hopsAway[0] === 0 Number of hops: {localFilterState.hopsAway[0] === 0
? "Direct" ? "Direct"
: filterState.hopsAway[0]} : localFilterState.hopsAway[0]}
{filterState.hopsAway[0] !== filterState.hopsAway[1] {localFilterState.hopsAway[0] !==
? " - " + filterState.hopsAway[1] localFilterState.hopsAway[1]
? " - " + localFilterState.hopsAway[1]
: ""} : ""}
</> </>
} }
@ -153,25 +184,26 @@ export function FilterControl({
<FilterSlider <FilterSlider
label="Last heard" label="Last heard"
filterKey="lastHeard" filterKey="lastHeard"
filterState={filterState} filterState={localFilterState}
defaultFilterValues={defaultFilterValues} defaultFilterValues={defaultFilterValues}
onChange={handleRangeChange} onChange={handleRangeChange}
labelContent={ labelContent={
<> <>
Last heard: <br /> Last heard: <br />
{filterState.lastHeard[0] === 0 ? "Now" : ( {localFilterState.lastHeard[0] === 0 ? "Now" : (
<> <>
{filterState.lastHeard[0] === {localFilterState.lastHeard[0] ===
defaultFilterValues.lastHeard[1] && ">"} defaultFilterValues.lastHeard[1] && ">"}
{formatTS(filterState.lastHeard[0])} {formatTS(localFilterState.lastHeard[0])}
</> </>
)} )}
{filterState.lastHeard[0] !== filterState.lastHeard[1] && ( {localFilterState.lastHeard[0] !==
localFilterState.lastHeard[1] && (
<> <>
{" – "} {" – "}
{filterState.lastHeard[1] === {localFilterState.lastHeard[1] ===
defaultFilterValues.lastHeard[1] && ">"} defaultFilterValues.lastHeard[1] && ">"}
{formatTS(filterState.lastHeard[1])} {formatTS(localFilterState.lastHeard[1])}
</> </>
)} )}
</> </>
@ -197,42 +229,42 @@ export function FilterControl({
<FilterSlider <FilterSlider
label="SNR (db)" label="SNR (db)"
filterKey="snr" filterKey="snr"
filterState={filterState} filterState={localFilterState}
defaultFilterValues={defaultFilterValues} defaultFilterValues={defaultFilterValues}
onChange={handleRangeChange} onChange={handleRangeChange}
/> />
<FilterSlider <FilterSlider
label="Channel Utilization (%)" label="Channel Utilization (%)"
filterKey="channelUtilization" filterKey="channelUtilization"
filterState={filterState} filterState={localFilterState}
defaultFilterValues={defaultFilterValues} defaultFilterValues={defaultFilterValues}
onChange={handleRangeChange} onChange={handleRangeChange}
/> />
<FilterSlider <FilterSlider
label="Airtime Utilization (%)" label="Airtime Utilization (%)"
filterKey="airUtilTx" filterKey="airUtilTx"
filterState={filterState} filterState={localFilterState}
defaultFilterValues={defaultFilterValues} defaultFilterValues={defaultFilterValues}
onChange={handleRangeChange} onChange={handleRangeChange}
/> />
<FilterSlider <FilterSlider
label="Battery level (%)" label="Battery level (%)"
filterKey="batteryLevel" filterKey="batteryLevel"
filterState={filterState} filterState={localFilterState}
defaultFilterValues={defaultFilterValues} defaultFilterValues={defaultFilterValues}
onChange={handleRangeChange} onChange={handleRangeChange}
labelContent={ labelContent={
<> <>
Battery level (%): {filterState.batteryLevel[0] === 101 Battery level (%): {localFilterState.batteryLevel[0] === 101
? "Plugged in" ? "Plugged in"
: filterState.batteryLevel[0]} : localFilterState.batteryLevel[0]}
{filterState.batteryLevel[0] !== {localFilterState.batteryLevel[0] !==
filterState.batteryLevel[1] && ( localFilterState.batteryLevel[1] && (
<> <>
{" – "} {" – "}
{filterState.batteryLevel[1] === 101 {localFilterState.batteryLevel[1] === 101
? "Plugged in" ? "Plugged in"
: filterState.batteryLevel[1]} : localFilterState.batteryLevel[1]}
</> </>
)} )}
</> </>
@ -241,7 +273,7 @@ export function FilterControl({
<FilterSlider <FilterSlider
label="Battery voltage (V)" label="Battery voltage (V)"
filterKey="voltage" filterKey="voltage"
filterState={filterState} filterState={localFilterState}
defaultFilterValues={defaultFilterValues} defaultFilterValues={defaultFilterValues}
onChange={handleRangeChange} onChange={handleRangeChange}
/> />

Loading…
Cancel
Save