react-pdf icon indicating copy to clipboard operation
react-pdf copied to clipboard

Conditionally Rendering PDF Elements Breaks App (Uncaught Error: Eo is not a function)

Open angelplusultra opened this issue 7 months ago • 8 comments

Description:

I'm encountering an issue when attempting to implement conditional rendering of sections within a @react-pdf/renderer Document. My goal is to allow users to toggle different parts of the PDF on or off dynamically.

When I remove elements from the PDF based on user interaction (e.g., a toggle switch), the application crashes with the following error:

Uncaught Error: Eo is not a function
    at Yr (reconciler-31.js:3220:155)
    at Yr (reconciler-31.js:3220:48)
    at Yr (reconciler-31.js:3220:48)
    at kl (reconciler-31.js:3705:25)
    at yl (reconciler-31.js:3633:29)
    at bl (reconciler-3657:21)
    at yl (reconciler-31.js:3637:70)
    at bl (reconciler-31.js:3657:21)
    at yl (reconciler-31.js:3637:70)
    at bl (reconciler-31.js:3657:21)
    at yl (reconciler-31.js:3637:70)
    at bl (reconciler-31.js:3657:21)
    at yl (reconciler-31.js:3637:70)
    at bl (reconciler-31.js:3648:21)
    at Jl (reconciler-31.js:4216:35)
    at eval (reconciler-31.js:4183:38)
    at ql (reconciler-31.js:4184:18)
    at _l (reconciler-3897:13)
    at El (reconciler-31.js:3884:29)
    at se (reconciler-31.js:707:31)
    at ae (reconciler-31.js:657:92)
    at _a.flushSyncWork (reconciler-5328:48)
    at Object.updateContainer (reconciler-31.js:5402:50)
    at Object.updateContainer (react-pdf.browser.js:190:14)
    at eval (react-pdf.browser.js:411:25)
    at eval (react-pdf.browser.js:427:58)
    at GeneratedResumeDocument (PDF.tsx:350:21)
    at GeneratedResumePage (page.tsx:81:10)

The error appears to originate within the PDFViewer component's rendering process.

Expected Behavior:

When I toggle a section off, the corresponding elements within the PDF should be removed, and the PDF should update dynamically without crashing.

Actual Behavior:

Removing elements from the PDF component due to conditional rendering causes the application to crash with the "Uncaught Error: Eo is not a function" error.

Heres a simple example that would cause the error:

const MyDocument = () => {

    const [enabled, setEnabled] = React.useState(true);

    return (

        <>
            <div>
                <button onClick={() => setEnabled(!enabled)}></button>
            </div>
            <PDFViewer style={{ height: '100vh', width: '100vw' }}>
                <Document>
                    <Page size="A4" style={styles.page}>
                        {enabled && <View style={styles.section}>
                            <Text>Section #1</Text>
                        </View>}
                        <View style={styles.section}>
                            <Text>Section #2</Text>
                        </View>
                    </Page>
                </Document>

            </PDFViewer>
        </>
    )
};

Clicking the button to toggle this to be removed and throw the error

angelplusultra avatar May 23 '25 19:05 angelplusultra

I've discovered that this bug only occurs when you conditionally remove elements from the PDF, but adding or moving around elements does not throw the error.

angelplusultra avatar Jun 04 '25 07:06 angelplusultra

I have the same problem, when I add an item, no bug, but when I delete an item, I have the same problem.

React-PDF uses a custom renderer based on react-reconciler (v0.31 for React 19), and element removal isn't handled properly, hence the crash. In short, instead of properly "repainting" the PDF after element removal, the engine tries to modify the existing structure and fails, resulting in the cryptic "Eo is not a function" error.

https://stackoverflow.com/questions/79583113/typeerror-eo-is-not-a-function-when-deleting-in-react-pdf

usadou29 avatar Jun 04 '25 12:06 usadou29

any solution??

ktisakib avatar Sep 01 '25 14:09 ktisakib

Add a key:

https://stackoverflow.com/questions/79583113/typeerror-eo-is-not-a-function-when-deleting-in-react-pdf

usadou29 avatar Sep 03 '25 05:09 usadou29

What is the solution to this?

sagorcnits avatar Sep 24 '25 17:09 sagorcnits

Having the same bug issue.... Eo is not a funcition

I'm working on a feature that convert lexical editorState to react-pdf-render Document in order to download as pdf, the editorState is a json with nested child and props according to the editor that i map over... I want to implement here a "rendering on the fly" as described in the docs

for debugging purpose it comes down to that:

import { usePDF, Document, Page, View, Text, Font } from "@react-pdf/renderer";
import { Button } from "@/components/ui/button";
import { Spinner } from "@/components/ui/spinner";
import type { SerializedEditorState } from "lexical";

// font register logic....

const InitialDoc = (
  <Document key={"inital-document"} style={{ fontFamily: "OpenSans", direction: "rtl" }}>
    <Page key={"inital-page"} style={{ padding: 30, direction: "rtl", textAlign: "right" }}>
      <Text key={"inital-text"} >inital-PDF</Text>
    </Page>
  </Document>
);

const DownloadPdfButton = ({
  disabledFromParent,
  editorState,
}: {
  disabledFromParent: boolean;
  editorState: SerializedEditorState;
}) => {
  const [instance, updateInstance] = usePDF({ document: InitialDoc }); // <----- **READ UPDATE!**
  const [pendingDownload, setPendingDownload] = useState(false);

  const isLoading = instance.loading;
  const isError = !!instance.error;

  const onClickHandler = () => {
    updateInstance(
      <Document key={"new-document"} style={{ fontFamily: "OpenSans", direction: "rtl" }}>
        <Page key={"new-page"} style={{ padding: 30, direction: "rtl" }}>
          <Text key={"pdf-row-1"}>1</Text>
          <Text key={"pdf-row-2"}>2</Text>
          <Text key={"pdf-row-3"}>3</Text>
          <Text key={"pdf-row-4"}>4</Text>
          <Text key={"pdf-row-5"}>5</Text>
        </Page>
      </Document>

       //////////// your downloading logic something like: ///////////
      const a = document.createElement("a");
      a.href = instance.url;
      a.download = "document.pdf";
      document.body.appendChild(a);
      a.click();
      document.body.removeChild(a);
      //////////////////////////////////////////////////////////////////////////////////////
    );
  };

  const label = isLoading ? "creating PDF..." : isError ? "error-PDF" : "download PDF";

  return (
    <Button variant="outline" size="sm" onClick={onClickHandler} disabled={isLoading || isError || disabledFromParent}>
      {isLoading ? <Spinner className="h-4 w-4" /> : <Download className="h-4 w-4" />}
      {label}
    </Button>
  );
};

export default DownloadPdfButton;

UPDATE: while writing this issue comment (after 2~3 days of research i saw posts that say conditional removing pdf comp from doc causing the bug) I found out setting the InitialDoc cause the bug, instead i wrote: const [instance, updateInstance] = usePDF();

ChipLuxury-EWA avatar Oct 10 '25 08:10 ChipLuxury-EWA

Suggest the best packages to generate PDF files with multiple pages, including tables, images, and links.

Viyass avatar Oct 15 '25 06:10 Viyass

The issue I face is with HMR in NextJS (doubt it's Next specific, but I have yet to try outside Next), the PDF renders fine but when I save a change with the PDF rendered, it gets this error, had to use the ref counter hack to force a full re-render for the PDFViewer.

https://stackoverflow.com/a/79653680

But the solution in stackoverflow only helped mitigate the issue, it still broke from time to time, so for HMR issues I went with a build constant timestamp:

// HMR-safe build epoch: changes on module reloads (dev), stable in prod runtime
const DEV_BUILD_EPOCH = Date.now();

export function EncounterPDFShowModal({ encounter }: EncounterPDFModalsProps) {
  return (
    <Dialog>
      <DialogTrigger asChild>
        <Button variant="ghost" size="sm" className="p-1">
          <EyeIcon className=" text-amber-700" />
        </Button>
      </DialogTrigger>

      <DialogContent className="w-auto min-w-[60vw] max-w-none sm:max-w-none mx-auto my-auto">
        <DialogHeader>
          <DialogTitle>Encounter PDF</DialogTitle>
        </DialogHeader>

        <PDFViewer key={DEV_BUILD_EPOCH}>
          <EncounterPDFDocument encounter={encounter} />
        </PDFViewer>
      </DialogContent>
    </Dialog>
  );
}

If you go this route, remember to give its own key to the download link, I wasted about 2 hours until I read the stackoverflow comment again.

carlos-vitallink360 avatar Oct 26 '25 22:10 carlos-vitallink360