LoginSignup
45
35

More than 3 years have passed since last update.

react-to-printを使ってReact.jsでDOMを印刷する

Posted at

はじめに

みなさん印刷してますか?
私は印刷していません。
印刷しようがしまいが、エンドユーザからは印刷機能を求められるものです。
今日は電子データ化、電子署名など一切を忘れましょう。

さて、帳票を印刷する際に使うツールとしてまず思いつくのはPDF、Excelでしょうか。
しかし、システムをユーザへ提供するし易さ、スピードで最も良いインターフェースはWebアプリケーションです。
というわけで React.js で帳票を印刷します。

Webアプリケーションで印刷するということ

Webアプリケーションで印刷を行う際に真っ先に思いつくのは、BackEndで印刷用ファイル(PDF)を生成し、FrontEndはそれをダウンロード・PDFViewerで印刷といった流れでしょうか。
今回はこれは行いません。

一方で、Webブラウザにはそれ独自の印刷機能が付いています。
この印刷機能はWebページ=DOMを直接印刷してくれるようです。

というわけで DOMを印刷します。

イメージ:↓の「3. FrontEndで帳票作成」
print_cases.png

つかうもの

react-to-print を選択した理由としては、SampleCodeで Class Component/Functional Component の両者に言及されていたからです。
React Hook :heart_exclamation:

その他、簡易的なデザイン付けのため、いつもお世話になっている material-uiを使用します。

成果物

Demoについて

print_demo.png

プロフィールカードに「プレビュー」と「印刷」ボタンが表示されています。

  • プレビュー:プレビュー画面を出してから印刷出来ます
  • 印刷:直接印刷画面を出します。

印刷画面はブラウザの機能に依存します。

概要

プレビュー画面


        <DialogTitle id="alert-dialog-title">{`${src.name}のプロフィールを印刷しますか?`}</DialogTitle>
        <DialogContent>
          <Print ref={componentRef} src={src} />
        </DialogContent>
        <DialogActions>
          <Button onClick={handleClose} color="primary">
            キャンセル
          </Button>
          <ReactToPrint
            trigger={() => (
              <Button size="small" color="primary">
                印刷
              </Button>
            )}
            content={() => componentRef.current}
          />
        </DialogActions>

プレビュー画面はDialogで表示しています。
印刷対象のComponentは Print で定義しています。

          <Print ref={componentRef} src={src} />

印刷機能を提供してくれるのは ReactToPrint です。


          <ReactToPrint
            trigger={() => (
              <Button size="small" color="primary">
                印刷
              </Button>
            )}
            content={() => componentRef.current}
          />

ReactToPrint のcontentに先ほどの Print を渡します。
その際、componentRef を経由していますが、これはuseRef()でrefオブジェクトを渡しています。

preview_demo.png

印刷画面

      <CardActions>
        <ReactToPrint
          trigger={() => (
            <Button size="small" color="primary">
              印刷
            </Button>
          )}
          content={() => componentRef.current}
        />
        <div style={{ display: "none" }}>
          <Print ref={componentRef} src={src} />
        </div>
      </CardActions>

直接印刷する際にはPrint を表示する必要がないのでdisplay: "none"で非表示にしています。

        <div style={{ display: "none" }}>
          <Print ref={componentRef} src={src} />
        </div>

chromeだとこうでます。
print_view_demo.png

メリット

  • 画面構成と印刷内容構成を同時に実装できる
  • CSSでデザインできる
  • なんかおしゃれな気がする
  • BackEnd処理が軽くなる

デメリット

  • 印刷設定ができない(?)
    ※今回使用したreact-to-print単体ではできませんが、CSSを駆使すれば出来るかも :thinking:

【補足】実はプレビューしないとCSSの反映が完璧ではない

今回、display: "none"を使用してプレビューを出さずに印刷する方法を提示しましたが、そうするとCSSが想定とずれることがあります。

プレビューしてから印刷 直接印刷
print_preview_ver.png print_direct_ver.png

上図では氏名とoutlineが重なっています。

# ただ、プレビューせずに印刷することは力技でやっているので自業自得感はあります :cry:

おわりに

React.jsに印刷機能を持たせてみました。
自作の職務経歴書くらいはかんたんに作れそうですね :grinning:
みなさんも良き印刷ライフを

45
35
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
45
35