fix: extracting debounced update to a custom hook

This commit is contained in:
auraofdivinity 2024-09-22 18:33:01 +05:30
parent 24b8bcf1ba
commit dbf1fb002f
3 changed files with 86 additions and 55 deletions

View File

@ -32,7 +32,13 @@ import {
DiagramModel,
DiagramModelGenerics,
} from "@projectstorm/react-diagrams";
import { SyntheticEvent, useEffect, useRef, useState } from "react";
import {
SyntheticEvent,
useCallback,
useEffect,
useRef,
useState,
} from "react";
import { useTranslation } from "react-i18next";
import { DeleteDialog } from "@/app-components/dialogs";
@ -45,13 +51,13 @@ import { getDisplayDialogs, useDialog } from "@/hooks/useDialog";
import { useSearch } from "@/hooks/useSearch";
import { EntityType, Format } from "@/services/types";
import { IBlock } from "@/types/block.types";
import { ICategory } from "@/types/category.types";
import { ICategory, ICategoryAttributes } from "@/types/category.types";
import { BlockPorts } from "@/types/visual-editor.types";
import BlockDialog from "../BlockDialog";
import { ZOOM_LEVEL } from "../constants";
import { useVisualEditor } from "../hooks/useVisualEditor";
import { RequestQueue } from "@/utils/requestQueue";
import useDebouncedUpdate from "@/hooks/useDebouncedUpdate";
const Diagrams = () => {
const { t } = useTranslation();
@ -110,26 +116,37 @@ const Diagrams = () => {
invalidate: false,
});
const requestQueue = useRef(new RequestQueue<ICategory>());
const enqueueUpdate = (id: string, params: any) => {
requestQueue.current.enqueue(() => updateCategory({ id, params }));
};
const debouncedUpdateCategory = useDebouncedUpdate(updateCategory, 300);
const debouncedZoomEvent = useCallback(
(event: any) => {
if (selectedCategoryId) {
engine?.repaintCanvas();
debouncedUpdateCategory({
id: selectedCategoryId,
params: {
zoom: event.zoom,
},
});
}
event.stopPropagation();
},
[selectedCategoryId, debouncedUpdateCategory],
);
const debouncedOffsetEvent = useCallback(
(event: any) => {
if (selectedCategoryId) {
debouncedUpdateCategory({
id: selectedCategoryId,
params: {
offset: [event.offsetX, event.offsetY],
},
});
}
event.stopPropagation();
},
[selectedCategoryId, debouncedUpdateCategory],
);
const debouncedZoomEvent = debounce((event) => {
if (selectedCategoryId) {
engine?.repaintCanvas();
enqueueUpdate(selectedCategoryId, { zoom: event.zoom });
}
event.stopPropagation();
}, 200);
const debouncedOffsetEvent = debounce((event) => {
if (selectedCategoryId) {
enqueueUpdate(selectedCategoryId, {
offset: [event.offsetX, event.offsetY],
});
}
event.stopPropagation();
}, 200);
const getBlockFromCache = useGetFromCache(EntityType.BLOCK);
const updateCachedBlock = useUpdateCache(EntityType.BLOCK);
const deleteCachedBlock = useDeleteFromCache(EntityType.BLOCK);

View File

@ -0,0 +1,47 @@
import { debounce } from "@mui/material";
import { useCallback, useEffect, useRef } from "react";
type DebouncedUpdateParams = {
id: string;
params: Record<string, any>;
};
function useDebouncedUpdate(
apiUpdate: (params: DebouncedUpdateParams) => void,
delay: number = 300,
) {
const accumulatedUpdates = useRef<DebouncedUpdateParams | null>(null);
const processUpdates = useRef(
debounce(() => {
if (accumulatedUpdates.current) {
apiUpdate(accumulatedUpdates.current);
accumulatedUpdates.current = null;
}
}, delay),
).current;
const handleUpdate = useCallback(
(params: DebouncedUpdateParams) => {
accumulatedUpdates.current = {
id: params.id,
params: {
...(accumulatedUpdates.current?.params || {}),
...params.params,
},
};
processUpdates();
},
[processUpdates],
);
useEffect(() => {
return () => {
processUpdates.clear();
};
}, [processUpdates]);
return handleUpdate;
}
export default useDebouncedUpdate;

View File

@ -1,33 +0,0 @@
/*
* Copyright © 2024 Hexastack. All rights reserved.
*
* Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms:
* 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission.
* 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file).
* 3. SaaS Restriction: This software, or any derivative of it, may not be used to offer a competing product or service (SaaS) without prior written consent from Hexastack. Offering the software as a service or using it in a commercial cloud environment without express permission is strictly prohibited.
*/
export class RequestQueue<T> {
private queue: Array<() => Promise<T>> = [];
private isProcessing = false;
enqueue(request: () => Promise<T>) {
this.queue.push(request);
this.processQueue();
}
private async processQueue() {
if (this.isProcessing) return;
this.isProcessing = true;
while (this.queue.length > 0) {
const request = this.queue.shift();
if (request) {
await request();
}
}
this.isProcessing = false;
}
}