6

I'm trying to use a npm library that help me to render a pdf document. I found react-pdf but it doesn't have the types for TypeScript yet, so I'm using it as I show below:

let Document = require('react-pdf');
let Page = require('react-pdf');

class PdfViewer extends React.Component<PdfViewer.Props, PdfViewer.State> {

  constructor(props: PdfViewer.Props) {
    super(props);
    this.state = {
      numPages: null,
      pageNumber: 1,
    };

  }
  onDocumentLoadSuccess = ( numPages: number ) => {
    this.setState({ numPages });

  }

  componentWillReceiveProps(nextProps: PdfViewer.Props) {
    // this.setState(CsvViewer.parse(nextProps.data));
  }

  render() {
      const {url} = this.props;
      const { pageNumber, numPages } = this.state;

      const buffer = data as ArrayBuffer;

      return ( 
      <div>
        <Document
          file={url}
          onLoadSuccess={this.onDocumentLoadSuccess}
        >
          <Page pageNumber={pageNumber} />
        </Document>
        <p>Page {pageNumber} of {numPages}</p>
      </div>
      );

  }
}

But it's throwing this error:

Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.

I found this in GitHub but it didn't help me to much. I went to the documentation of the library, and I passed an object in the file parameter as they show to do but the same error. I think is something else. I went to the source code of the react-pdf library and I think this is the function they use to get the file from the parameter:

findDocumentSource = async () => {
    const { file } = this.props;

    if (!file) {
      return null;
    }

    // File is a string
    if (typeof file === 'string') {
      if (isDataURI(file)) {
        const fileUint8Array = dataURItoUint8Array(file);
        return { data: fileUint8Array };
      }

      displayCORSWarning();
      return { url: file };
    }

    // File is PDFDataRangeTransport
    if (file instanceof PDFDataRangeTransport) {
      return { range: file };
    }

    // File is an ArrayBuffer
    if (isArrayBuffer(file)) {
      return { data: file };
    }

    /**
     * The cases below are browser-only.
     * If you're running on a non-browser environment, these cases will be of no use.
     */
    if (isBrowser) {
      // File is a Blob
      if (isBlob(file) || isFile(file)) {
        return { data: await loadFromFile(file) };
      }
    }

    // At this point, file must be an object
    if (typeof file !== 'object') {
      throw new Error('Invalid parameter in file, need either Uint8Array, string or a parameter object');
    }

    if (!file.url && !file.data && !file.range) {
      throw new Error('Invalid parameter object: need either .data, .range or .url');
    }

    // File .url is a string
    if (typeof file.url === 'string') {
      if (isDataURI(file.url)) {
        const { url, ...otherParams } = file;
        const fileUint8Array = dataURItoUint8Array(url);
        return { data: fileUint8Array, ...otherParams };
      }

      displayCORSWarning();
    }

    return file;
  };

But I doubt the error is here but I can't figure out what could be. The version of react I'm using is 16.8.2 and 4.0.2 for react-pdf

2 Answers 2

7

This is incorrect:

let Document = require('react-pdf');
let Page = require('react-pdf');

You are importing the entire module when you do this. That means that Document and Page both contain all the modules of react-pdf. Instead what you want to do is either import ReactPDF and reference those modules:

const ReactPDF = require('react-pdf');

<ReactPDF.Document />
<ReactPDF.Page />

or you could use destructuring:

import { Document, Page } from 'react-pdf';

//or

const { Document, Page } = require('react-pdf'); 

If TypeScript complains about missing declarations, just add a @types folder to your project, create a subfolder inside of it called react-pdf and file inside that folder called index.d.ts with one line:

declare module "react-pdf"
Sign up to request clarification or add additional context in comments.

4 Comments

let me try that
I tried now your second suggestion but I got this:` Try npm install @types/react-pdf if it exists or add a new declaration (.d.ts) file containing declare module 'react-pdf' . I created the @types folder in the src folder, should I put it outside at the same level of node_modules?
I always put mine in src so the full path would be ./src/@types/react-pdf/index.d.ts but I'm not sure if it actually matters where it is at all
My bad, I stopped and started again the project and it worked, thanks again
3
  • first add types
  • if you are using create react app you should add:
import { Document, Page, pdfjs } from "react-pdf/dist/esm/entry.webpack";
pdfjs.GlobalWorkerOptions.workerSrc =`//cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.js`;

1 Comment

Where does this solution come from (the react-pdf docs?), and why does it work?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.