An Interval is declared in a useEffect. This interval goes ahead and conditionally sets the src property on an iframe, referenced by useRef. The goal is to reload the iframe, if it hasn’t been loaded yet.
import { useEffect, useRef, useState } from "react";
import { useParams } from "react-router-dom";
import { getRemoteUrl } from "../utils/getRemoteUrl";
import { mapUrl } from "../utils/mapUrl";
interface Props {
setUrl: React.Dispatch<React.SetStateAction<string>>;
}
const PdfViewer = (props: Props) => {
const ref = useRef<HTMLIFrameElement>(null);
const { filename, encoded } = useParams();
const [loaded, setLoaded] = useState(false);
const intervalId = useRef<NodeJS.Timer | null>(null);
useEffect(() => {
if (encoded && filename) {
const decodedUrl = decodeURIComponent(encoded);
const mappedUrl = mapUrl(decodedUrl);
props.setUrl(mappedUrl);
const localUrl = `${mappedUrl}/${encodeURIComponent(filename)}`;
const iframeUrl = `https://docs.google.com/gview?url=${getRemoteUrl(
localUrl
)}&embedded=true`;
const iframe = ref.current;
if (iframe) {
iframe.src = iframeUrl;
if (intervalId.current) clearInterval(intervalId.current);
intervalId.current = setInterval(() => {
if (!loaded) {
iframe.src = iframeUrl;
} else if (intervalId.current) {
clearInterval(intervalId.current);
}
}, 5000);
}
return () => {
if (intervalId.current) {
clearInterval(intervalId.current);
}
};
}
}, [filename, encoded, props.setUrl, loaded]);
if (!filename) {
return <h1>No file found</h1>;
}
return (
<div className="flex flex-col">
<p className="text-center">
This might take a while. Try refreshing the page periodically.
<br></br>If the file is not loading, try{" "}
<a
className="underline"
href={getRemoteUrl(
mapUrl(decodeURIComponent(encoded!)) +
`/${encodeURIComponent(filename)}`
)}
>
downloading it.
</a>
</p>
<iframe
ref={ref}
className="w-full h-[80vh]"
title="pdf"
onLoad={() => {
setLoaded(true);
}}
></iframe>
</div>
);
};
export default PdfViewer;
Expected: When the iframe loads, “loaded” becomes true and thus no further request to docs.google.com will be made.
Reality: No matter what, every 5 seconds a request is made to docs.google.com sometimes returning as a 200 and refreshing the iframe, making the app unusable.
2