From 3b5ca3da330d3878d128b1f6739f241efdc88aaa Mon Sep 17 00:00:00 2001 From: satoshi toyama Date: Wed, 30 Oct 2024 18:22:34 +0900 Subject: [PATCH] refactor(graph): Inline debounce logic in GraphProvider Simplify state management by removing separate useDebounce hook and incorporating debouncing directly in the GraphProvider component. The functionality remains the same but with cleaner code organization. Key changes: - Remove standalone useDebounce hook - Add timeout handling directly in enhancedDispatch - Clean up timeout on component unmount - Fix potential memory leak by clearing timeout between state updates The 500ms debounce delay for graph updates is preserved. --- .../p/[agentId]/beta-proto/graph/provider.tsx | 42 +++++++++++-------- .../beta-proto/graph/use-debounce.ts | 30 ------------- 2 files changed, 24 insertions(+), 48 deletions(-) delete mode 100644 app/(playground)/p/[agentId]/beta-proto/graph/use-debounce.ts diff --git a/app/(playground)/p/[agentId]/beta-proto/graph/provider.tsx b/app/(playground)/p/[agentId]/beta-proto/graph/provider.tsx index 2072d744..b75909ac 100644 --- a/app/(playground)/p/[agentId]/beta-proto/graph/provider.tsx +++ b/app/(playground)/p/[agentId]/beta-proto/graph/provider.tsx @@ -11,7 +11,6 @@ import { type EnhancedDispatch, GraphContext } from "./context"; import { graphReducer } from "./reducer"; import { setGraphToDb } from "./server-actions"; import type { Graph } from "./types"; -import { useDebounce } from "./use-debounce"; const initialState = { graph: { @@ -34,25 +33,32 @@ export const GraphProvider: FC> = ({ const isInitialMount = useRef(true); const stateRef = useRef({ graph: defaultGraph }); const [state, setState] = useState(stateRef.current); + const timeoutRef = useRef(null); - const deboucedSetGraphToDb = useDebounce(async (graph: Graph) => { - setGraphToDb(agentId, graph); - }, 500); - const enhancedDispatch: EnhancedDispatch = useCallback(async (action) => { - if (typeof action === "function") { - await action(enhancedDispatch, () => stateRef.current); - } else { - stateRef.current = graphReducer(stateRef.current, action); - } - setState(stateRef.current); - }, []); + const enhancedDispatch: EnhancedDispatch = useCallback( + async (action) => { + if (typeof action === "function") { + await action(enhancedDispatch, () => stateRef.current); + } else { + stateRef.current = graphReducer(stateRef.current, action); + if (timeoutRef.current) { + clearTimeout(timeoutRef.current); + } + timeoutRef.current = setTimeout(async () => { + await setGraphToDb(agentId, stateRef.current.graph); + }, 500); + } + setState(stateRef.current); + }, + [agentId], + ); useEffect(() => { - if (isInitialMount.current) { - isInitialMount.current = false; - } else { - deboucedSetGraphToDb(stateRef.current.graph); - } - }, [deboucedSetGraphToDb]); + return () => { + if (timeoutRef.current) { + clearTimeout(timeoutRef.current); + } + }; + }, []); return ( {children} diff --git a/app/(playground)/p/[agentId]/beta-proto/graph/use-debounce.ts b/app/(playground)/p/[agentId]/beta-proto/graph/use-debounce.ts deleted file mode 100644 index 9a54bb46..00000000 --- a/app/(playground)/p/[agentId]/beta-proto/graph/use-debounce.ts +++ /dev/null @@ -1,30 +0,0 @@ -// useDebounce.ts -import { useCallback, useEffect, useRef } from "react"; - -// biome-ignore lint: lint/suspicious/noExplicitAny -export function useDebounce any>( - callback: T, - delay: number, -): T { - const timeoutRef = useRef(null); - - useEffect(() => { - return () => { - if (timeoutRef.current) { - clearTimeout(timeoutRef.current); - } - }; - }, []); - - return useCallback( - (...args: Parameters) => { - if (timeoutRef.current) { - clearTimeout(timeoutRef.current); - } - timeoutRef.current = setTimeout(() => { - callback(...args); - }, delay); - }, - [callback, delay], - ) as T; -}