Skip to content

Instantly share code, notes, and snippets.

@gitname
Last active June 10, 2024 09:20
Show Gist options
  • Save gitname/bdc1fb7fe5bd0c22f6656b7905f57cd6 to your computer and use it in GitHub Desktop.
Save gitname/bdc1fb7fe5bd0c22f6656b7905f57cd6 to your computer and use it in GitHub Desktop.
Using `@react-pdf/renderer` with React 18

Using @react-pdf/renderer v3.0.1 with React 18

Introduction

When I tried to use the @react-pdf/renderer package (version 3.0.1) with a React 18 app, two problems arose. In this article, I'll describe those problems and tell you how I solved them.

Update: Here's a video demonstration of the problems and solution described in this article: https://youtu.be/YZP5r7Uy_bU

Problem 1: Dependency Conflict

According to its package.json file, the @react-pdf/renderer package (as of version 3.0.1—the latest version) is only compatible with React versions 16 and 17. Meanwhile, React apps created using create-react-app (as of version 5.0.1—the latest version) run React version 18.

Trying to install the @react-pdf/renderer package into such an app results in a dependency conflict:

$ npm install @react-pdf/renderer
...
npm ERR! Could not resolve dependency:
npm ERR! peer react@"^16.8.6 || ^17.0.0" from @react-pdf/renderer@3.0.1
npm ERR! node_modules/@react-pdf/renderer
npm ERR!   @react-pdf/renderer@"*" from the root project

Solution A: Use --legacy-peer-deps option

Note: I recommend Solution B. I am only documenting Solution A for reference, since I have seen several people propose it.

One workaround people have proposed is that developers use the --legacy-peer-deps option when installing the @react-pdf/renderer package. I don't like this approach because (a) it requires me to include that command-line option every time I install any package after that; and (b) it skips peer dependency checks for all packages, not just for @react-pdf/renderer.

$ npm install @react-pdf/renderer --legacy-peer-deps

Solution B: Use overrides property

A different workaround—and the one I prefer—is to use the overrides property in my app's package.json file. This tells NPM that @react-pdf/renderer really depends upon React 18. Unlike with the other workaround; here, (a) the "override" remains documented in package.json and (b) only the @react-pdf/renderer package and its descendants are affected.

  "overrides": {
    "@react-pdf/renderer": {
      "react": "^18.0.0"
    }
  },
$ npm install @react-pdf/renderer

Problem 2: Inaccurate TypeScript types

Note: If you are not using TypeScript, you can ignore this problem.

The type definitions of some components in the @react-pdf/renderer package were written under the assumption that any component whose type was React.Component would implictly accept a children prop. Some people refer to that implict acceptance of a children prop as "implicit children."

The "implicit children" behavior was removed from React in React 18. However, the type definitions in the @react-pdf/renderer package have not been updated accordingly.

As a result, trying to render any of the affected components with child elements, like this...

import { Svg } from "@react-pdf/renderer";

const MyComponent = () => (
  <Svg>
    {/* child elements go here */}
  </Svg>
);

...results in a compiler error:

TS2769: No overload matches this call.
...
Property 'children' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes<Svg> & Readonly<SVGProps>'

Solution: Use custom components

To work around that, I define and use custom variants of the affected components. These custom variants do accept a children prop.

To define the custom variants, I copy/paste the following code into any .tsx file in my app's src/ folder (personally, I put it in a new file at src/patches/@react-pdf/renderer/index.tsx):

import ReactPDF from '@react-pdf/renderer';
import { FC, PropsWithChildren } from 'react';

// Custom variants of `@react-pdf/renderer` components, which accept a `children` prop.
//
// Credits: Special thanks to GitHub user @antoineharel for sharing this solution at:
//          https://github.com/diegomura/react-pdf/pull/1798#issuecomment-1259552615

export const Svg: FC<PropsWithChildren<ReactPDF.SVGProps>> = ({ ...props }) => (
  <ReactPDF.Svg {...props} />
);

export const G: FC<PropsWithChildren<ReactPDF.GProps>> = ({ ...props }) => (
  <ReactPDF.G {...props} />
);

export const ClipPath: FC<PropsWithChildren<ReactPDF.ClipPathProps>> = ({ ...props }) => (
  <ReactPDF.ClipPath {...props} />
);

Now, whenever I would normally import any of the affected components, I import the custom variant instead of the original @react-pdf/renderer variant:

  import { 
    Svg 
- } from "@react-pdf/renderer";
+ } from "../patches/@react-pdf/renderer";

  const MyComponent = () => (
    <Svg>
      {/* child elements go here */}
    </Svg>
  );

Conclusion

With the above solutions in place, I use @react-pdf/renderer with React 18.

@mdtaju
Copy link

mdtaju commented Jan 9, 2023

Thank you. All are ok in my development server. But, I'm facing a problem in production mode. I used option 'b' in my case.
And I used this >

import {
      Image, Text,
      View
} from "@react-pdf/renderer";
import JsBarcode from "jsbarcode";
....
....
<View>
             <Image source={barcode} alt="Barcode" />
</View>

In my production mode error is below (Production in cPanel).
Screenshot 2023-01-09 101337
Screenshot 2023-01-09 101318

@gitname
Copy link
Author

gitname commented Jan 11, 2023

Hi @mdtaju, I have not come across that error. I have used the workaround (with option "b") in both development and production without issue. I wonder whether the error you encountered is due to some other package you are using. I have some suggestions:

  1. Check whether a bare-bones React 18 app + @react-pdf/renderer works in both your development and production environment. You can follow along with the video linked in the Gist in order to create the bare-bones app.
  2. Then, start introducing the additional packages you use (test the app in both environments after adding each additional package), until you encounter the error.
  3. Next, remove the other, non-offending packages until you have the most bare-bones app that still exhibits the error (I think this will make it easier for others to understand your situation and to help you).
  4. Finally, create an "Issue" in the offending package's repository, reporting the error and (if possible) providing a link to your code and/or the deployed app.

@chhavientrar
Copy link

image

hii i am trying to use the watermark but its showing the blank is it possible to create the watermark with this lib.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment