mirror of
https://github.com/stan-smith/FossFLOW.git
synced 2025-12-23 22:48:57 -05:00
Fix ExportImageDialog infinite re-render loop (#98)
* fix: eliminate re-render loop causing export failures - Remove onModelUpdated callback that triggered infinite re-render cycles - Replace debounce hack with controlled useEffect-based export timing - Ensure DOM stability before export execution to prevent null containerRef - Add isExporting guard to prevent concurrent export operations Resolves issue where image export functionality was completely broken due to infinite re-rendering caused by onModelUpdated callback. Fixes #84 Huge thanks are attributed to @jibbex for resolving this issue!
This commit is contained in:
committed by
GitHub
parent
627fe2e690
commit
c626261e3e
@@ -40,7 +40,7 @@ interface Props {
|
||||
|
||||
export const ExportImageDialog = ({ onClose, quality = 1.5 }: Props) => {
|
||||
const containerRef = useRef<HTMLDivElement>();
|
||||
const debounceRef = useRef<NodeJS.Timeout>();
|
||||
const isExporting = useRef<boolean>(false);
|
||||
const currentView = useUiStateStore((state) => {
|
||||
return state.view;
|
||||
});
|
||||
@@ -65,33 +65,24 @@ export const ExportImageDialog = ({ onClose, quality = 1.5 }: Props) => {
|
||||
});
|
||||
}, [uiStateActions]);
|
||||
|
||||
const exportImage = useCallback(async () => {
|
||||
if (!containerRef.current) return;
|
||||
const exportImage = useCallback(() => {
|
||||
if (!containerRef.current || isExporting.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
clearTimeout(debounceRef.current);
|
||||
debounceRef.current = setTimeout(() => {
|
||||
exportAsImage(containerRef.current as HTMLDivElement)
|
||||
.then((data) => {
|
||||
return setImageData(data);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
setExportError(true);
|
||||
});
|
||||
}, 2000);
|
||||
isExporting.current = true;
|
||||
exportAsImage(containerRef.current as HTMLDivElement)
|
||||
.then((data) => {
|
||||
setImageData(data);
|
||||
isExporting.current = false;
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
setExportError(true);
|
||||
isExporting.current = false;
|
||||
});
|
||||
}, []);
|
||||
|
||||
const downloadFile = useCallback(() => {
|
||||
if (!imageData) return;
|
||||
|
||||
const data = base64ToBlob(
|
||||
imageData.replace('data:image/png;base64,', ''),
|
||||
'image/png;charset=utf-8'
|
||||
);
|
||||
|
||||
downloadFileUtil(data, generateGenericFilename('png'));
|
||||
}, [imageData]);
|
||||
|
||||
const [showGrid, setShowGrid] = useState(false);
|
||||
const handleShowGridChange = (checked: boolean) => {
|
||||
setShowGrid(checked);
|
||||
@@ -104,10 +95,37 @@ export const ExportImageDialog = ({ onClose, quality = 1.5 }: Props) => {
|
||||
setBackgroundColor(color);
|
||||
};
|
||||
|
||||
// Reset image data when options change and trigger export
|
||||
useEffect(() => {
|
||||
setImageData(undefined);
|
||||
setExportError(false);
|
||||
isExporting.current = false;
|
||||
const timer = setTimeout(() => {
|
||||
exportImage();
|
||||
}, 100);
|
||||
|
||||
return () => clearTimeout(timer);
|
||||
}, [showGrid, backgroundColor]);
|
||||
|
||||
useEffect(() => {
|
||||
const timer = setTimeout(() => {
|
||||
exportImage();
|
||||
}, 100);
|
||||
|
||||
return () => clearTimeout(timer);
|
||||
}, []);
|
||||
|
||||
const downloadFile = useCallback(() => {
|
||||
if (!imageData) return;
|
||||
|
||||
const data = base64ToBlob(
|
||||
imageData.replace('data:image/png;base64,', ''),
|
||||
'image/png;charset=utf-8'
|
||||
);
|
||||
|
||||
downloadFileUtil(data, generateGenericFilename('png'));
|
||||
}, [imageData]);
|
||||
|
||||
return (
|
||||
<Dialog open onClose={onClose}>
|
||||
<DialogTitle>Export as image</DialogTitle>
|
||||
@@ -146,7 +164,6 @@ export const ExportImageDialog = ({ onClose, quality = 1.5 }: Props) => {
|
||||
>
|
||||
<Isoflow
|
||||
editorMode="NON_INTERACTIVE"
|
||||
onModelUpdated={exportImage}
|
||||
initialData={{
|
||||
...model,
|
||||
fitToView: true,
|
||||
@@ -235,4 +252,4 @@ export const ExportImageDialog = ({ onClose, quality = 1.5 }: Props) => {
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user