refactor: optimize drawing data handling and cache management

- Improve cache key generation using JSON.stringify for consistent formatting
- Add promise deduplication in DrawingCard to prevent redundant API calls for full drawing data
- Clear full data state when drawing ID changes to ensure fresh data loading
- Fix async cache invalidation in drawing update and collection delete endpoints
- Move cache invalidation after database operations in SQLite import endpoint
- Add HydratedDrawingData type for better type safety in drawing data management
This commit is contained in:
Adrian Acala
2025-11-29 11:35:57 -08:00
parent 6f050aec7d
commit c4352185d6
2 changed files with 39 additions and 19 deletions
+31 -13
View File
@@ -10,6 +10,12 @@ import { exportDrawingToFile } from '../utils/exportUtils';
import * as api from '../api';
type HydratedDrawingData = {
elements: any[];
appState: any;
files: Record<string, any>;
};
interface DrawingCardProps {
drawing: DrawingSummary;
collections: Collection[];
@@ -52,27 +58,39 @@ export const DrawingCard: React.FC<DrawingCardProps> = ({
const [previewSvg, setPreviewSvg] = useState<string | null>(drawing.preview ?? null);
const [contextMenu, setContextMenu] = useState<{ x: number; y: number } | null>(null);
const [isExporting, setIsExporting] = useState(false);
const [fullData, setFullData] = useState<{
elements: any[];
appState: any;
files: Record<string, any> | null;
} | null>(null);
const [fullData, setFullData] = useState<HydratedDrawingData | null>(null);
const fullDataRef = React.useRef(fullData);
fullDataRef.current = fullData;
const fullDataPromiseRef = React.useRef<Promise<HydratedDrawingData> | null>(null);
useEffect(() => {
setFullData(null);
fullDataPromiseRef.current = null;
}, [drawing.id]);
const ensureFullData = useCallback(async () => {
if (fullDataRef.current) {
return fullDataRef.current;
}
const fullDrawing = await api.getDrawing(drawing.id);
const payload = {
elements: fullDrawing.elements || [],
appState: fullDrawing.appState || {},
files: fullDrawing.files || {},
};
setFullData(payload);
return payload;
if (fullDataPromiseRef.current) {
return fullDataPromiseRef.current;
}
const promise = api.getDrawing(drawing.id).then((fullDrawing) => {
const payload: HydratedDrawingData = {
elements: fullDrawing.elements || [],
appState: fullDrawing.appState || {},
files: fullDrawing.files || {},
};
setFullData(payload);
fullDataPromiseRef.current = null;
return payload;
}).catch((error) => {
fullDataPromiseRef.current = null;
throw error;
});
fullDataPromiseRef.current = promise;
return promise;
}, [drawing.id]);
useEffect(() => {