auto save fix
deploy to danak / build_and_deploy (push) Has been cancelled

This commit is contained in:
hamid zarghami
2026-06-20 12:59:39 +03:30
parent e93ab38b05
commit b13a46ec65
4 changed files with 15 additions and 19 deletions
+12 -4
View File
@@ -67,6 +67,14 @@ export const useUpdateCatalog = () => {
mutationFn: api.updateCatalog, mutationFn: api.updateCatalog,
}); });
// Ref to always hold the latest mutation without adding it to useCallback/useEffect deps.
// React Query's useMutation returns a new object reference on every render, so
// closing over `mutation` directly would cause scheduleUpdate and the cleanup effect
// to be recreated/re-run on every render — firing mutation.mutate on each re-render
// during drag (potentially 100+ times).
const mutationRef = useRef(mutation);
mutationRef.current = mutation;
const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null); const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
const pendingParamsRef = useRef< const pendingParamsRef = useRef<
Parameters<typeof api.updateCatalog>[0] | null Parameters<typeof api.updateCatalog>[0] | null
@@ -96,11 +104,11 @@ export const useUpdateCatalog = () => {
pendingParamsRef.current = null; pendingParamsRef.current = null;
setIsScheduledSaving(false); setIsScheduledSaving(false);
if (pendingParams) { if (pendingParams) {
mutation.mutate(pendingParams); mutationRef.current.mutate(pendingParams);
} }
}, delayMs); }, delayMs);
}, },
[mutation], [],
); );
useEffect( useEffect(
@@ -112,12 +120,12 @@ export const useUpdateCatalog = () => {
// اگر کاربر قبل از پایان debounce از ادیتور خارج شد، // اگر کاربر قبل از پایان debounce از ادیتور خارج شد،
// آخرین تغییرات معلق را همان لحظه ذخیره کن. // آخرین تغییرات معلق را همان لحظه ذخیره کن.
if (pendingParamsRef.current) { if (pendingParamsRef.current) {
mutation.mutate(pendingParamsRef.current); mutationRef.current.mutate(pendingParamsRef.current);
pendingParamsRef.current = null; pendingParamsRef.current = null;
} }
setIsScheduledSaving(false); setIsScheduledSaving(false);
}, },
[mutation], [],
); );
return { return {
@@ -64,11 +64,7 @@ const AbstractShape = ({ obj, isSelected, onSelect, onUpdate, draggable }: Shape
} }
}} }}
onDragMove={(e) => { onDragMove={(e) => {
const node = e.target; e.target.getLayer()?.batchDraw();
onUpdate(obj.id, {
x: node.x() - (obj.width || 100) / 2,
y: node.y() - (obj.height || 100) / 2,
});
}} }}
onDragEnd={(e) => { onDragEnd={(e) => {
const node = e.target; const node = e.target;
@@ -53,11 +53,7 @@ const CircleShape = ({ obj, isSelected, onSelect, onUpdate, draggable }: ShapePr
} }
}} }}
onDragMove={(e) => { onDragMove={(e) => {
const node = e.target; e.target.getLayer()?.batchDraw();
onUpdate(obj.id, {
x: node.x(),
y: node.y(),
});
}} }}
onDragEnd={(e) => { onDragEnd={(e) => {
const node = e.target; const node = e.target;
@@ -60,11 +60,7 @@ const TriangleShape = ({ obj, isSelected, onSelect, onUpdate, draggable }: Shape
} }
}} }}
onDragMove={(e) => { onDragMove={(e) => {
const node = e.target; e.target.getLayer()?.batchDraw();
onUpdate(obj.id, {
x: node.x() - (obj.width || 100) / 2,
y: node.y() - (obj.height || 100) / 2,
});
}} }}
onDragEnd={(e) => { onDragEnd={(e) => {
const node = e.target; const node = e.target;