implement custom hook

This commit is contained in:
Josh Hawkins 2024-04-04 09:33:12 -05:00
parent 4f0a7d961a
commit f91116df52
3 changed files with 56 additions and 9 deletions

View File

@ -2,7 +2,7 @@ import { Button } from "../ui/button";
import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover"; import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover";
import useSWR from "swr"; import useSWR from "swr";
import { CameraGroupConfig, FrigateConfig } from "@/types/frigateConfig"; import { CameraGroupConfig, FrigateConfig } from "@/types/frigateConfig";
import { useCallback, useEffect, useMemo, useState } from "react"; import { useCallback, useMemo, useState } from "react";
import { import {
DropdownMenu, DropdownMenu,
DropdownMenuContent, DropdownMenuContent,
@ -29,6 +29,7 @@ import ReviewActivityCalendar from "../overlay/ReviewActivityCalendar";
import MobileReviewSettingsDrawer, { import MobileReviewSettingsDrawer, {
DrawerFeatures, DrawerFeatures,
} from "../overlay/MobileReviewSettingsDrawer"; } from "../overlay/MobileReviewSettingsDrawer";
import useOptimisticState from "@/hooks/use-optimistic-state";
const REVIEW_FILTERS = [ const REVIEW_FILTERS = [
"cameras", "cameras",
@ -631,12 +632,10 @@ function ShowMotionOnlyButton({
motionOnly, motionOnly,
setMotionOnly, setMotionOnly,
}: ShowMotionOnlyButtonProps) { }: ShowMotionOnlyButtonProps) {
const [motionOnlyButton, setMotionOnlyButton] = useState(motionOnly); const [motionOnlyButton, setMotionOnlyButton] = useOptimisticState(
motionOnly,
useEffect(() => { setMotionOnly,
const timeoutId = setTimeout(() => setMotionOnly(motionOnlyButton), 10); );
return () => clearTimeout(timeoutId);
}, [motionOnlyButton, setMotionOnly]);
return ( return (
<> <>

View File

@ -0,0 +1,43 @@
import { useState, useEffect, useCallback, useRef } from "react";
type OptimisticStateResult<T> = [T, (newValue: T) => void];
const useOptimisticState = <T>(
initialState: T,
setState: (newValue: T) => void,
delay: number = 20,
): OptimisticStateResult<T> => {
const [optimisticValue, setOptimisticValue] = useState<T>(initialState);
const debounceTimeout = useRef<ReturnType<typeof setTimeout> | null>(null);
const handleValueChange = useCallback(
(newValue: T) => {
// Update the optimistic value immediately
setOptimisticValue(newValue);
// Clear any pending debounce timeout
if (debounceTimeout.current) {
clearTimeout(debounceTimeout.current);
}
// Set a new debounce timeout
debounceTimeout.current = setTimeout(() => {
// Update the actual value using the provided setter function
setState(newValue);
}, delay);
},
[delay, setState],
);
useEffect(() => {
return () => {
if (debounceTimeout.current) {
clearTimeout(debounceTimeout.current);
}
};
}, []);
return [optimisticValue, handleValueChange];
};
export default useOptimisticState;

View File

@ -41,6 +41,7 @@ import { RecordingStartingPoint } from "@/types/record";
import VideoControls from "@/components/player/VideoControls"; import VideoControls from "@/components/player/VideoControls";
import { TimeRange } from "@/types/timeline"; import { TimeRange } from "@/types/timeline";
import { useCameraMotionNextTimestamp } from "@/hooks/use-camera-activity"; import { useCameraMotionNextTimestamp } from "@/hooks/use-camera-activity";
import useOptimisticState from "@/hooks/use-optimistic-state";
type EventViewProps = { type EventViewProps = {
reviews?: ReviewSegment[]; reviews?: ReviewSegment[];
@ -199,6 +200,10 @@ export default function EventView({
); );
const [motionOnly, setMotionOnly] = useState(false); const [motionOnly, setMotionOnly] = useState(false);
const [severityToggle, setSeverityToggle] = useOptimisticState(
severity,
setSeverity,
);
if (!config) { if (!config) {
return <ActivityIndicator />; return <ActivityIndicator />;
@ -214,9 +219,9 @@ export default function EventView({
className="*:px-3 *:py-4 *:rounded-md" className="*:px-3 *:py-4 *:rounded-md"
type="single" type="single"
size="sm" size="sm"
value={severity} value={severityToggle}
onValueChange={(value: ReviewSeverity) => onValueChange={(value: ReviewSeverity) =>
value ? setSeverity(value) : null value ? setSeverityToggle(value) : null
} // don't allow the severity to be unselected } // don't allow the severity to be unselected
> >
<ToggleGroupItem <ToggleGroupItem