LoginSignup
2
1

react-pdf/rendererを使って、作成したpdfを新規タブに表示する

Last updated at Posted at 2024-02-08

ReactでPDFを作成し、それを新規タブに表示させる方法についてです。
react-pdfで検索した際に困ったため、記事にしてみようと思い立ちました。

バージョン

  • vite: 4.4.5
  • React: 18.2.0
  • TypeScript: 5.0.2
  • react-pdf/renderer: 3.1.15

コード

当初はchatGPTさんに手伝ってもらったものを改良して行きました。
ですが記事を書く際に公式ドキュメントを見ていると、BlobProviderなるものが提供されていたので、そちらを使用した例も自戒を込めて記載します。
ちゃんとドキュメント読んで♡

なお関数等の処理はカスタムフックとして他の処理と一緒に読み込もうとして少し苦戦したので、メモがてら以下コードもそのようになっております。

作成するPDF

適当に、一枚ずつ数字が書かれているpdfを作成します。
引数は[1, 2, 3]のようなnumberの配列を取るようになっています。

PDF.tsx
import { Document, Page, Text } from "@react-pdf/renderer";

export const Pdf = ({ data }: { data: number[] }) => (
  <Document>
    {data.map((item) => (
      <Page key={item}>
        <Text>{item}</Text>
      </Page>
    ))}
  </Document>
);

pdfを使用した方法

index.tsx
import { Pdf } from "./Pdf";
import { PrintButton } from "./PrintButton";

function App () {
  return <PrintButton element={<Pdf data={[1, 2, 3, 4, 5]} />} />
};

export default App;
PrintButton.tsx
import { usePrintButton } from "./usePrintButton";

export const PrintButton = ({ element }: { element: JSX.Element }) => {
  const { handlePrintPDF } = usePrintButton(element);

  return <button onClick={handlePrintPDF}>印刷する</button>;
};
usePrintButton.ts
import { pdf } from "@react-pdf/renderer";

type UsePrintButton = {
  handlePrintPDF: () => void;
};

export const usePrintButton = (element: JSX.Element): UsePrintButton => {
  const handlePrintPDF = async () => {
    try {
      const blob = await pdf(element).toBlob();
      const url = URL.createObjectURL(blob);
      window.open(url, "_blank");
    } catch (error) {
      console.error("Error handing nameplate printing:", error);
    }
  };

  return { handlePrintPDF };
};

解説

そもそもblobとは何ぞ

Blob = Binary Large OBject
通常のデータ型に格納できないバイナリデータを格納するためのデータ型です。

JavaScriptでも同様にバイナリデータを扱うオブジェクトとして使用できるそうです。

ちなみに、このBlobへのアクセス先をURLとして表示させることを「Blob URL Schema」と呼ぶそうです。
このURLを作成しているのが、ここではURL.createObjectURL(blob)となります。

usePrintButton.tsについて

pdfを利用して、受け取ったエレメントのblobデータを作成しています。
それをURLcreateObjectURLによりURLでアクセスできるようにし、window.openメソッドにより新規タブで該当urlを開くようになっています。

BlobProviderを使用した方法

index.tsx
import { UsingBlobProvider } from "./UsingBlobProvider";

function App() {
  return <UsingBlobProvider />
}

export default App;
UsingBlobProvider.tsx
import { BlobProvider } from "@react-pdf/renderer";
import { Pdf } from "./Pdf";

export const UsingBlobProvider = () => {
  const handlePrintPdf = (url: string | null) => {
    if (url) {
      const newWindow = window.open(url, "_blank");
    } else {
      alert("URL is null");
    }
  };

  return (
    <>
      <BlobProvider document={<Pdf data={[1, 2, 3, 4, 5, 6, 7, 8]} />}>
        {({ url }) => (
          <div onClick={() => handlePrintPdf(url)}>
            <span>印刷する</span>
          </div>
        )}
      </BlobProvider>
    </>
  );
};

解説

BlobProvider

BlobProviderdocument属性に作成したPDFを渡し、そのタグの中でchildrenであるurlをonClickの関数に渡しています。
こっちの方がスッキリしてますね()

childrenには他にもblobやloading, errorが使用出来るようです。

参考リンク

  • BlobProvider

  • 公式ドキュメント

  • blobについて

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1