PDFViewer does not render until reloaded
Describe the bug
-
I have used the <PDFViewer> to display the PDF in the web app but on the first render the PDFViewer is not shown.
-
I have to reload sometimes even multiple times
-
I have a condition that checks if the data from the API has arrived before rendering the DOM so I dont think its because of that.
-
If there are any loading states that I am missing do let me know
-
Below is the code snippet
if (
!queryResult.data ||
queryResult.isLoading ||
!userData ||
isLoading ||
!window
)
return <LoadingScreen />;
return (
<div className="w-screen min-h-screen bg-white grid text-black">
<Container maxWidth="md" className="py-6 px-0 h-full">
<PDFViewer height={600} width={"100%"}>
<ReportPDF
pdfTitle={props.reportTitle}
reportTitle={props.reportTitle}
data={parsedData}
tableHead={TABLE_HEAD}
user={{
address: userData.address ? CombineAddress(userData.address) : "",
avatar: userData.avatar,
name: ConstructFullName(
userData.firstName,
userData.middleName,
userData.lastName
),
role: role.key,
}}
companyInfo={{
name:
role.key === "superadmin"
? "ABC"
: (role.role?.companyName ?? ""),
logo:
(role.key === "superadmin"
? LOGOS.MMD
: role.role?.companyLogo) ?? LOGOS.MMD,
}}
/>
</PDFViewer>
</Container>
</div>
);
Screenshots
First Render =>
After Reloading =>
Desktop (please complete the following information):
- OS: Mac, Windows, Linux
- Browser Chrome
- React-pdf version 7.7.3
- @react-pdf/renderer": "^3.4.5
It looks like your PDFViewer component isn't rendering properly on the first load, requiring multiple reloads. Since you already have a condition ensuring data availability before rendering, the issue might be related to:
-
Delayed API Response / Query Inconsistencies
- Even though
queryResult.isLoadingis checked, sometimes React Query updates state asynchronously, andqueryResult.datamight still beundefinedmomentarily. - Try adding a console log to verify the state before rendering:
console.log("Query Result:", queryResult); console.log("User Data:", userData); console.log("Window:", typeof window !== "undefined");
- Even though
-
windowCheck & SSR Issues- If you're using Next.js or any SSR framework, the
windowobject is only available on the client side. - Try ensuring that
PDFVieweris rendered only on the client:import dynamic from "next/dynamic"; const PDFViewer = dynamic(() => import("@react-pdf/renderer").then((mod) => mod.PDFViewer), { ssr: false });
- If you're using Next.js or any SSR framework, the
-
Force Re-render on Data Change
- The
PDFViewermight not be updating properly when data arrives. - Try forcing a re-render using
useEffectanduseState:const [readyToRender, setReadyToRender] = useState(false); useEffect(() => { if (queryResult.data && userData) { setReadyToRender(true); } }, [queryResult.data, userData]); if (!readyToRender) return <LoadingScreen />;
- The
-
Check for
ReportPDFIssues- Ensure
parsedData,TABLE_HEAD, anduserare not undefined before passing them toReportPDF. - Wrap
ReportPDFinside auseMemohook to avoid unnecessary re-renders:const memoizedPDF = useMemo(() => ( <ReportPDF pdfTitle={props.reportTitle} reportTitle={props.reportTitle} data={parsedData} tableHead={TABLE_HEAD} user={{ address: userData.address ? CombineAddress(userData.address) : "", avatar: userData.avatar, name: ConstructFullName( userData.firstName, userData.middleName, userData.lastName ), role: role.key, }} companyInfo={{ name: role.key === "superadmin" ? "ABC" : (role.role?.companyName ?? ""), logo: (role.key === "superadmin" ? LOGOS.MMD : role.role?.companyLogo) ?? LOGOS.MMD, }} /> ), [parsedData, userData, role, props.reportTitle]); return ( <PDFViewer height={600} width={"100%"}> {memoizedPDF} </PDFViewer> );
- Ensure
Final Steps to Debug:
- Check console logs to verify state changes.
- Use
useEffectto trackqueryResult.dataupdates. - Try delaying rendering slightly using
setTimeout(() => setReady(true), 500); - Ensure that React-PDF dependencies are correctly installed.
It looks like your PDFViewer component isn't rendering properly on the first load, requiring multiple reloads. Since you already have a condition ensuring data availability before rendering, the issue might be related to:
-
Delayed API Response / Query Inconsistencies
- Even though
queryResult.isLoadingis checked, sometimes React Query updates state asynchronously, andqueryResult.datamight still beundefinedmomentarily. - Try adding a console log to verify the state before rendering:
console.log("Query Result:", queryResult); console.log("User Data:", userData); console.log("Window:", typeof window !== "undefined");
- Even though
-
windowCheck & SSR Issues- If you're using Next.js or any SSR framework, the
windowobject is only available on the client side. - Try ensuring that
PDFVieweris rendered only on the client:import dynamic from "next/dynamic"; const PDFViewer = dynamic(() => import("@react-pdf/renderer").then((mod) => mod.PDFViewer), { ssr: false });
- If you're using Next.js or any SSR framework, the
-
Force Re-render on Data Change
- The
PDFViewermight not be updating properly when data arrives. - Try forcing a re-render using
useEffectanduseState:const [readyToRender, setReadyToRender] = useState(false); useEffect(() => { if (queryResult.data && userData) { setReadyToRender(true); } }, [queryResult.data, userData]); if (!readyToRender) return <LoadingScreen />;
- The
-
Check for
ReportPDFIssues- Ensure
parsedData,TABLE_HEAD, anduserare not undefined before passing them toReportPDF. - Wrap
ReportPDFinside auseMemohook to avoid unnecessary re-renders:const memoizedPDF = useMemo(() => ( <ReportPDF pdfTitle={props.reportTitle} reportTitle={props.reportTitle} data={parsedData} tableHead={TABLE_HEAD} user={{ address: userData.address ? CombineAddress(userData.address) : "", avatar: userData.avatar, name: ConstructFullName( userData.firstName, userData.middleName, userData.lastName ), role: role.key, }} companyInfo={{ name: role.key === "superadmin" ? "ABC" : (role.role?.companyName ?? ""), logo: (role.key === "superadmin" ? LOGOS.MMD : role.role?.companyLogo) ?? LOGOS.MMD, }} /> ), [parsedData, userData, role, props.reportTitle]); return ( <PDFViewer height={600} width={"100%"}> {memoizedPDF} </PDFViewer> );
- Ensure
Final Steps to Debug:
- Check console logs to verify state changes.
- Use
useEffectto trackqueryResult.dataupdates. - Try delaying rendering slightly using
setTimeout(() => setReady(true), 500); - Ensure that React-PDF dependencies are correctly installed.
It looks like your PDFViewer component isn't rendering properly on the first load, requiring multiple reloads. Since you already have a condition ensuring data availability before rendering, the issue might be related to:
Delayed API Response / Query Inconsistencies
- Even though
queryResult.isLoadingis checked, sometimes React Query updates state asynchronously, andqueryResult.datamight still beundefinedmomentarily.- Try adding a console log to verify the state before rendering: console.log("Query Result:", queryResult); console.log("User Data:", userData); console.log("Window:", typeof window !== "undefined");
windowCheck & SSR Issues
If you're using Next.js or any SSR framework, the
windowobject is only available on the client side.Try ensuring that
PDFVieweris rendered only on the client: import dynamic from "next/dynamic";const PDFViewer = dynamic(() => import("@react-pdf/renderer").then((mod) => mod.PDFViewer), { ssr: false });
Force Re-render on Data Change
The
PDFViewermight not be updating properly when data arrives.Try forcing a re-render using
useEffectanduseState: const [readyToRender, setReadyToRender] = useState(false);useEffect(() => { if (queryResult.data && userData) { setReadyToRender(true); } }, [queryResult.data, userData]);
if (!readyToRender) return <LoadingScreen />;
Check for
ReportPDFIssues
Ensure
parsedData,TABLE_HEAD, anduserare not undefined before passing them toReportPDF.Wrap
ReportPDFinside auseMemohook to avoid unnecessary re-renders: const memoizedPDF = useMemo(() => ( <ReportPDF pdfTitle={props.reportTitle} reportTitle={props.reportTitle} data={parsedData} tableHead={TABLE_HEAD} user={{ address: userData.address ? CombineAddress(userData.address) : "", avatar: userData.avatar, name: ConstructFullName( userData.firstName, userData.middleName, userData.lastName ), role: role.key, }} companyInfo={{ name: role.key === "superadmin" ? "ABC" : (role.role?.companyName ?? ""), logo: (role.key === "superadmin" ? LOGOS.MMD : role.role?.companyLogo) ?? LOGOS.MMD, }} /> ), [parsedData, userData, role, props.reportTitle]);return ( <PDFViewer height={600} width={"100%"}> {memoizedPDF} </PDFViewer> );
Final Steps to Debug:
- Check console logs to verify state changes.
- Use
useEffectto trackqueryResult.dataupdates.- Try delaying rendering slightly using
setTimeout(() => setReady(true), 500);- Ensure that React-PDF dependencies are correctly installed.
Thank you very much for the detailed reply so basically what I did was the loading state that we get from the PDFDownloadLink component i stored it in a local state and used it as a loading indicator for the pdf as well which solved the issue