Search code examples
javascriptreactjsreact-hooksreact-pdf

React pdf responsiveness using React Hooks, but when increasing or decreasing window size I get this TypeError


import React, { useState, useRef, useEffect } from 'react';
import throttle from 'lodash/throttle';
import { Document, Page } from 'react-pdf/dist/esm/entry.webpack';
import 'react-pdf/dist/esm/Page/AnnotationLayer.css';

export default function PDFWrapper({ data, onDocumentLoadSuccess, pageNumber }) {
  const [initialWidth, setInitialWidth] = useState(null);
  const pdfWrapper = useRef();

  const setPdfSize = () => {
    setInitialWidth(pdfWrapper.current.getBoundingClientRect().width);
  };

  useEffect(() => {
    window.addEventListener('resize', throttle(setPdfSize, 3000));
    setPdfSize();
    return () => {
      window.removeEventListener('resize', throttle(setPdfSize, 3000));
    };
  });

  return (
    <div
      id="row"
      style={{
        height: '100vh', display: 'flex',
      }}
    >
      <div id="placeholderWrapper" style={{ height: '100vh' }} />
      <div id="pdfWrapper" style={{ width: '90vw' }} ref={pdfWrapper}>
        <Document
          file={data}
          onLoadSuccess={onDocumentLoadSuccess}
          noData=""
          loading=""
        >
          <Page pageNumber={pageNumber} loading="" width={initialWidth} />
        </Document>
      </div>
    </div>
  );
}

I will copy here the whole error. It looks like it is coming from setPdfSize function. NOTE:

TypeError: Cannot read property 'getBoundingClientRect' of null. 10 | const setPdfSize = () => { 11 | setInitialWidth(pdfWrapper.current.getBoundingClientRect().width); | ^ 12 | }; 13 | 14 | useEffect(() => { Any help will be appreciated.


Solution

  • Firstly I would add [] an empty dependency array to useEffect hook in order to run only once the component is mounted, probably you don't want to attach and detach several times the same event. Also I would check for null values at setPdfSize function because it's initially null.

    See from the useRef documentation:

    useRef returns a mutable ref object whose .current property is initialized to the passed argument (initialValue). The returned object will persist for the full lifetime of the component.

    I would try as the following:

    const pdfWrapper = useRef(null);
    
    const setPdfSize = () => {
      if (pdfWrapper && pdfWrapper.current) {
        setInitialWidth(pdfWrapper.current.getBoundingClientRect().width);
      }
    };
    
    useEffect(() => {
      window.addEventListener('resize', throttle(setPdfSize, 3000));
      setPdfSize();
      return () => {
        window.removeEventListener('resize', throttle(setPdfSize, 3000));
      };
    }, []);