mirror of
https://github.com/blakeblackshear/frigate.git
synced 2025-12-06 13:34:13 +03:00
fix race condition in detail stream context
navigating between tracked objects in Explore would sometimes prevent the object track from appearing
This commit is contained in:
parent
c3f242dc53
commit
c0f1fa1f61
@ -1,4 +1,10 @@
|
|||||||
import React, { createContext, useContext, useState, useEffect } from "react";
|
import React, {
|
||||||
|
createContext,
|
||||||
|
useContext,
|
||||||
|
useState,
|
||||||
|
useEffect,
|
||||||
|
useRef,
|
||||||
|
} from "react";
|
||||||
import { FrigateConfig } from "@/types/frigateConfig";
|
import { FrigateConfig } from "@/types/frigateConfig";
|
||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
|
|
||||||
@ -36,6 +42,23 @@ export function DetailStreamProvider({
|
|||||||
() => initialSelectedObjectIds ?? [],
|
() => initialSelectedObjectIds ?? [],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// When the parent provides a new initialSelectedObjectIds (for example
|
||||||
|
// when navigating between search results) update the selection so children
|
||||||
|
// like `ObjectTrackOverlay` receive the new ids immediately. We only
|
||||||
|
// perform this update when the incoming value actually changes.
|
||||||
|
useEffect(() => {
|
||||||
|
if (
|
||||||
|
initialSelectedObjectIds &&
|
||||||
|
(initialSelectedObjectIds.length !== selectedObjectIds.length ||
|
||||||
|
initialSelectedObjectIds.some((v, i) => selectedObjectIds[i] !== v))
|
||||||
|
) {
|
||||||
|
setSelectedObjectIds(initialSelectedObjectIds);
|
||||||
|
}
|
||||||
|
// Intentionally include selectedObjectIds to compare previous value and
|
||||||
|
// avoid overwriting user interactions unless the incoming prop changed.
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [initialSelectedObjectIds]);
|
||||||
|
|
||||||
const toggleObjectSelection = (id: string | undefined) => {
|
const toggleObjectSelection = (id: string | undefined) => {
|
||||||
if (id === undefined) {
|
if (id === undefined) {
|
||||||
setSelectedObjectIds([]);
|
setSelectedObjectIds([]);
|
||||||
@ -63,10 +86,33 @@ export function DetailStreamProvider({
|
|||||||
setAnnotationOffset(cfgOffset);
|
setAnnotationOffset(cfgOffset);
|
||||||
}, [config, camera]);
|
}, [config, camera]);
|
||||||
|
|
||||||
// Clear selected objects when exiting detail mode or changing cameras
|
// Clear selected objects when exiting detail mode or when the camera
|
||||||
|
// changes for providers that are not initialized with an explicit
|
||||||
|
// `initialSelectedObjectIds` (e.g., the RecordingView). For providers
|
||||||
|
// that receive `initialSelectedObjectIds` (like SearchDetailDialog) we
|
||||||
|
// avoid clearing on camera change to prevent a race with children that
|
||||||
|
// immediately set selection when mounting.
|
||||||
|
const prevCameraRef = useRef<string | undefined>(undefined);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
// Always clear when leaving detail mode
|
||||||
|
if (!isDetailMode) {
|
||||||
setSelectedObjectIds([]);
|
setSelectedObjectIds([]);
|
||||||
}, [isDetailMode, camera]);
|
prevCameraRef.current = camera;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If camera changed and the parent did not provide initialSelectedObjectIds,
|
||||||
|
// clear selection to preserve previous behavior.
|
||||||
|
if (
|
||||||
|
prevCameraRef.current !== undefined &&
|
||||||
|
prevCameraRef.current !== camera &&
|
||||||
|
initialSelectedObjectIds === undefined
|
||||||
|
) {
|
||||||
|
setSelectedObjectIds([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
prevCameraRef.current = camera;
|
||||||
|
}, [isDetailMode, camera, initialSelectedObjectIds]);
|
||||||
|
|
||||||
const value: DetailStreamContextType = {
|
const value: DetailStreamContextType = {
|
||||||
selectedObjectIds,
|
selectedObjectIds,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user