diff --git a/job-tracker-ui/src/pages/ProfilePage.tsx b/job-tracker-ui/src/pages/ProfilePage.tsx index 37ff125..3b35b00 100644 --- a/job-tracker-ui/src/pages/ProfilePage.tsx +++ b/job-tracker-ui/src/pages/ProfilePage.tsx @@ -267,15 +267,27 @@ export default function ProfilePage() { const [currentPassword, setCurrentPassword] = useState(""); const [newPassword, setNewPassword] = useState(""); + // Keep a ref to the latest carousel so the unmount cleanup can revoke the + // outstanding preview object URLs without re-running on every change. + const pdfCarouselRef = useRef([]); useEffect(() => { + pdfCarouselRef.current = pdfCarousel; + }, [pdfCarousel]); + + useEffect(() => { + // Revoke any remaining preview object URLs only on unmount. Per-change + // revocation is already handled explicitly in savePdfToCarousel (replace) and + // resetPdfCarousel (clear); doing it here on every pdfCarousel change revoked + // URLs that were still referenced by other items in the deck, breaking their + // previews. return () => { - pdfCarousel.forEach((item) => { + pdfCarouselRef.current.forEach((item) => { if (item.pdfUrl) { window.URL.revokeObjectURL(item.pdfUrl); } }); }; - }, [pdfCarousel]); + }, []); const loadProfile = useCallback(async () => { setLoading(true);