reactjstypescriptreact-pdf

"TypeError: Cannot perform Construct on a detached ArrayBuffer" when trying to set page count in React component


My component receives a file object and uses react-pdf to render it inside a div. The way it’s right now, it only displays the first page, because I have set the value so. Of course, I want to make it so it displays the whole file. This is what I’m trying:

/* eslint-disable @typescript-eslint/no-unused-vars */

import { Document, Page, pdfjs } from "react-pdf"
import { useState, useEffect, useCallback } from "react"
import SimpleBar from "simplebar-react"

pdfjs.GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.min.js`

interface PaperViewerProps {
  file: any
}

function PaperViewer({ file }: PaperViewerProps) {
  const [numPages, setNumPages] = useState()
  const [pageNumber, setPageNumber] = useState(1)
  const [arrayBuffer, setArrayBuffer] = useState<ArrayBuffer | null>(null)

  useEffect(() => {
    // Ensure file is a valid PDF
    if (!file || file.type !== "application/pdf") {
      return // Handle invalid file
    }

    const fileReader = new FileReader()
    fileReader.onload = (event) => {
      const receivedArrayBuffer = event.target?.result
      setArrayBuffer(receivedArrayBuffer as ArrayBuffer)
    }
    fileReader.readAsArrayBuffer(file)
  }, [file])

  const onDocumentLoadSuccess = ({ numPages }) => {
    setNumPages(numPages)
  }

  return (
    <div>
      {arrayBuffer && (
        <div className="w-full rounded-md shadow flex flex-col items-center">
          <div className="flex-1 w-full max-h-screen">
            <SimpleBar autoHide={false} className="max-h-[calc(100vh-10rem)]">
              <Document
                file={{ data: arrayBuffer }}
                className="flex justify-center"
                onLoadSuccess={onDocumentLoadSuccess}
              >
                <Page
                  pageNumber={pageNumber}
                  renderTextLayer={false}
                  renderAnnotationLayer={false}
                />
              </Document>
            </SimpleBar>
          </div>
        </div>
      )}
    </div>
  )
}

export default PaperViewer

Here, I am trying to set the total page count in the onDocumentLoadSuccess() method. However, it throws the following error:

TypeError: Cannot perform Construct on a detached ArrayBuffer

I even tried setting the value manually to a number like so:

const onDocumentLoadSuccess = (2) => {
    setNumPages(2)
  }

But the error persists. It seems the very act of calling setPageNum is causing the error. What am I doing wrong here?

I just realized that the error occurs every time there’s a page re-render, i.e., every time a variable is set through a useState setter. But why? And is there any way to prevent this error while also being able to set state values?


Solution

  • I was running into the same issue when using an ArrayBuffer as the file prop value.

    I tried converting the ArrayBuffer to base64string and that worked for me.

    First, convert the ArrayBuffer to a base64 string by doing this:

    base64String = Buffer.from(arrayBuffer, 'binary').toString('base64')

    Then, follow the steps in the react-pdf docs to set the file prop equal to the base64 string:

    https://github.com/wojtekmaj/react-pdf/wiki/Frequently-Asked-Questions#how-do-i-load-a-pdf-from-base64

    Hope that helps!