How to automatically save a file using react-pdf

2.3k Views Asked by At

Good evening everybody I'm creating a react app (to embed into a WordPress site, just in case you need this info) that gets some data from a form and than create a pdf file, via react-pdf module ( https://github.com/diegomura/react-pdf )

To make react-pdf compatible with React 18.2.0, I added a couple of lines to my package.json file, as suggested here (https://gist.github.com/gitname/bdc1fb7fe5bd0c22f6656b7905f57cd6 ):

"overrides": {
  "@react-pdf/renderer": {
    "react": "^18.2.0"
  }
 },

This file must be stored somewhere in the server, without giving any consent message to the user.

I tried using usePDF hook ( https://react-pdf.org/hooks )to get the instance.blob content, but now I don't know how to store it.

import React from "react";
import { usePDF, Page, Text, View, Document, StyleSheet } from "@react-pdf/renderer";

// Create styles
const styles = StyleSheet.create({ ... something ...});

// Create Document Component
const MyDocument = () => (
  <Document>
    <Page size="A4" style={styles.page}>
      <View style={styles.section}>
        <Text>
          Lorem ipsum dolor sit amet consectetur adipisicing elit. Neque, reprehenderit! 
        </Text>
      </View>
      <View style={styles.section}>
        <Text>
          Lorem ipsum dolor sit amet consectetur adipisicing elit.
        </Text>
      </View>
    </Page>
  </Document>
);

const MyPdfComponent = () => {
  const [instance, updateInstance] = usePDF({ document: <MyDocument /> });
 
  if (instance.loading) return <div>Loading ...</div>;
 
  if (instance.error) return <div>Something went wrong: {instance.error}</div>;

  if (instance.blob) {
    /* What can I put here? */

    return <div>PDF have been generated...</div>;
  }
};

export default MyPdfComponent;

According to the official docs, I first tried using this code:

import ReactPDF from '@react-pdf/renderer';
ReactPDF.render(<MyDocument />, `${__dirname}/example.pdf`);

But something goes wrong, because I have a message telling me that "render is a Node specific API. You're either using this method in a browser, or your bundler is not loading react-pdf from the appropriate web build."

I just need that the file is programmatically stored in a specific folder and the user is redirected to a success page (or something I have to implement...)

Any hint for that?

Tank you so much!

2

There are 2 best solutions below

0
Wallace Júnior On

If you are using Next.JS, you have to render this component only on the client, the hook usePDF only works client side.

You will have to import the component like so:

import dynamic from "next/dynamic";

const MyDocument = dynamic(async () => {
  const m = await import("path/to/MyDocument");

  // if no default export
  return m.MyDocument;

  // if default export
  return m.default;
},{ ssr:false });
0
Jobajuba On

Yow will need a package the allows you to save the file. "react-pdf" generates the pdf and "file-saver" allows you to download it.

See example code:

import { saveAs } from 'file-saver';
import { Page, Text, View, Document, StyleSheet, pdf } from '@react-pdf/renderer';

function savePDF() {
  try {
    const doc = (
      <Document>
        <Page>
          <Text>Hello, World!</Text>
        </Page>
      </Document>
    );

    const asPdf = pdf([]); // {} is important, throws without an argument
    asPdf.updateContainer(doc);
    const pdfBlob = asPdf.toBlob();
    saveAs(pdfBlob, 'document.pdf');
  } catch (error) {
    console.error(error);
    alert('Error generating PDF');
  }
}

function MyComponent() {
  return (
    <div>
      <button onClick={savePDF}>Save PDF</button>
    </div>
  );
}

export default MyComponent;

There is another more advanced version for larger file called "streamsaver". But file-saver should work well for your intended purpose.

You can also use custom stylesheet to style your text and views.