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/[email protected]
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.

@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