PDF ツール React で PDF ファイルを作成する方法 Darrius Serrant 更新日:7月 28, 2025 Download IronPDF npmダウンロード Start Free Trial Copy for LLMs Copy for LLMs Copy page as Markdown for LLMs Open in ChatGPT Ask ChatGPT about this page Open in Gemini Ask Gemini about this page Open in Grok Ask Grok about this page Open in Perplexity Ask Perplexity about this page Share Share on Facebook Share on X (Twitter) Share on LinkedIn Copy URL Email article React アプリケーションから PDF ドキュメントを作成するチュートリアルへようこそ! このチュートリアルでは、PDF を生成するさまざまなライブラリを探索し、人気のjsPDFライブラリを使用して React コンポーネントから直接 PDF ファイルを作成する方法を学びます。 それでは、始めましょう! PDF(Portable Document Format)は、ドキュメントのレイアウトとフォーマットを保持しながら共有および印刷するために広く使用されているファイル形式です。 React の Web 開発者として、請求書、レポート、販売契約などの PDF ドキュメントを React アプリケーションから直接生成する必要があるシナリオに遭遇するかもしれません。 React PDF ライブラリの選択 React アプリケーションで PDF ドキュメントを作成することは、特に新しいフィールドの場合は大変な作業です。 幸いなことに、このプロセスを大幅に簡素化するサードパーティのライブラリがいくつかあります。 各ライブラリには独自の機能とユーティリティが用意されており、さまざまなユースケースに対応しています。 これらのライブラリについてさらに詳しく見ていきましょう。 jsPDF jsPDFは、JavaScriptからPDFファイルを生成するために開発者の間で広く人気のあるライブラリです。 主なセールスポイントの 1 つはそのシンプルさです。 その構文と使用法は非常に簡単で、HTML コンテンツをすぐに PDF ファイルに変換できます。 フォントのサイズや色の変更、ページの向きやサイズの調整など、PDF の書式設定やレイアウトを制御できます。jsPDF は、ブラウザ環境とサーバー環境の両方で機能する堅牢なソリューションであり、幅広い JavaScript アプリケーションに最適な選択肢です。 pdfmake pdfmakeは、純粋な JavaScript で作成されたクライアント/サーバー側の PDF 印刷ソリューションとして際立っています。 このライブラリは、包括的な API と柔軟なレイアウトオプションのおかげで、より複雑な PDF を作成するための優れた選択肢です。 pdfmakeを使用すると、シンプルな JavaScript オブジェクトを使用してドキュメントのコンテンツと構造を定義し、それを有効な PDF ドキュメントに変換できます。 React-PDF React-PDFは、React コンポーネントを使用して PDF ファイルを作成するための強力な機能を提供するユニークなライブラリです。 JavaScript オブジェクトでドキュメント構造を手動で記述する代わりに、再利用可能なコンポーネントとプロップスを使用して、通常の React アプリケーションを構築するように PDF を作成できます。 IronPDF の Web サイトには、React-PDF ライブラリを使用した PDF の作成に関するチュートリアルがあります。 jsPDF を選ぶ理由 3 つのライブラリすべてが React で PDF ドキュメントを生成するための強力なツールを提供しますが、このチュートリアルでは、シンプルで柔軟性があり、コミュニティで広く採用されているため、jsPDF を使用します。 初心者にとって参入障壁が低く、その堅牢な機能セットにより多くのユースケースに適した選択となります。 jsPDFで調査する原則は、PDF を生成するための確固たる基盤を提供し、プロジェクトが要求する場合は、他のライブラリをより簡単に取り上げることができます。 前提条件 このチュートリアルに飛び込む前に、スムーズに進めるために必要なツールと知識が十分に装備されていることを確認することが重要です。 このチュートリアルの前提条件は次のとおりです。 React の基本的な理解 まず第一に、単一ページ アプリケーションを構築するための人気のある JavaScript ライブラリである React の基本的な理解が必要です。 React の JSX(JavaScript XML)、コンポーネント、状態、プロパティといった概念に精通している必要があります。 開発環境 また、React アプリケーションを構築するための開発環境をコンピューターに設定しておく必要があります。 これには、テキストエディタまたは統合開発環境 (IDE) が含まれます。 Visual Studio Code、Atom、Sublime Text などのテキスト エディターはすべて優れたオプションです。 Node.js と npm プロジェクトとその依存関係を管理するために、Node.js および npm (Node Package Manager) を使用します。 コンピューターに Node.js がインストールされていることを確認してください。 Node.jsは私たちがサーバー上でJavaScriptを実行できるようにするJavaScriptランタイムです。 これには npm がインストールされているので、プロジェクトに必要なライブラリを管理できます。 次の端末コマンドを実行して Node.js と npm がインストールされているかどうかを確認できます。 node -v npm -v node -v npm -v SHELL これらのコマンドは、システムにインストールされている Node.js および npm のバージョンを表示します。 インストールされていない場合やバージョンが古い場合は、公式ダウンロードページから最新の長期サポート (LTS) バージョンの Node.js をダウンロードしてインストールする必要があります。 ステップ 1: プロジェクトのセットアップ React プロジェクトのセットアップを開始しましょう。 ターミナルを開き、プロジェクトを作成したいディレクトリに移動します。 次のコマンドを実行して、新しい React アプリケーションを作成します。 npx create-react-app pdf-from-react npx create-react-app pdf-from-react SHELL このコマンドは、pdf-from-reactという名前の新しいディレクトリを作成し、基本的な React プロジェクト構造を持ちます。 次に、プロジェクトディレクトリに移動します。 cd pdf-from-react cd pdf-from-react SHELL これで、コードエディタでプロジェクトを開いて実装を進めることができます。 ステップ 2: 必要な依存関係の追加 まず、必要なパッケージをインストールする必要があります。 次のターミナルコマンドを使用して、react、react-dom、@mui/material、jspdfをインストールします。 npm install jspdf @mui/material @emotion/react @emotion/styled @mui/icons-material npm install jspdf @mui/material @emotion/react @emotion/styled @mui/icons-material SHELL ステップ 3: PDF 生成機能の構築 ライブラリのインポート アプリケーションに必要な依存関係をインポートすることから始めます。 これには、Material-UI ライブラリのさまざまなコンポーネント、PDF を生成するための jsPDF ライブラリ、およびスタイリングユーティリティが含まれます。 import React, { useState } from "react"; import "./App.css"; import { Button, TextField, Box, Container, Typography, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Paper, IconButton, Snackbar, Alert, } from "@mui/material"; import Grid from "@mui/material/Grid"; import DeleteIcon from "@mui/icons-material/Delete"; import jsPDF from "jspdf"; import { styled } from "@mui/material/styles"; import { tableCellClasses } from "@mui/material/TableCell"; import React, { useState } from "react"; import "./App.css"; import { Button, TextField, Box, Container, Typography, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Paper, IconButton, Snackbar, Alert, } from "@mui/material"; import Grid from "@mui/material/Grid"; import DeleteIcon from "@mui/icons-material/Delete"; import jsPDF from "jspdf"; import { styled } from "@mui/material/styles"; import { tableCellClasses } from "@mui/material/TableCell"; JAVASCRIPT スタイル付きコンポーネントの作成 アプリに一貫性のあるクロスブラウザー動作を追加するために、MUI ライブラリの styled ユーティリティを使用して StyledTableCell と StyledTableRow を作成しています。 const StyledTableCell = styled(TableCell)(({ theme }) => ({ [`&.${tableCellClasses.head}`]: { backgroundColor: theme.palette.common.black, color: theme.palette.common.white, }, [`&.${tableCellClasses.body}`]: { fontSize: 14, }, })); const StyledTableRow = styled(TableRow)(({ theme }) => ({ "&:nth-of-type(odd)": { backgroundColor: theme.palette.action.hover, }, "&:last-child td, &:last-child th": { border: 0, }, })); const StyledTableCell = styled(TableCell)(({ theme }) => ({ [`&.${tableCellClasses.head}`]: { backgroundColor: theme.palette.common.black, color: theme.palette.common.white, }, [`&.${tableCellClasses.body}`]: { fontSize: 14, }, })); const StyledTableRow = styled(TableRow)(({ theme }) => ({ "&:nth-of-type(odd)": { backgroundColor: theme.palette.action.hover, }, "&:last-child td, &:last-child th": { border: 0, }, })); JAVASCRIPT App コンポーネントの作成 このアプリケーションのメインコンポーネントはAppコンポーネントです。 ここでは 4 つの状態変数を使用しています。カスタマーのデータを追跡するための customerName と customerAddress、インボイスのアイテムリストを追跡するための items、必要に応じてエラーメッセージを表示するための error です。 function App() { // State variables const [customerName, setCustomerName] = useState(""); const [customerAddress, setCustomerAddress] = useState(""); const [items, setItems] = useState([{ name: "", quantity: "", price: "" }]); const [error, setError] = useState(false); function App() { // State variables const [customerName, setCustomerName] = useState(""); const [customerAddress, setCustomerAddress] = useState(""); const [items, setItems] = useState([{ name: "", quantity: "", price: "" }]); const [error, setError] = useState(false); JAVASCRIPT ユーザー入力の処理 このコードブロックでは、ユーザーの操作を処理するための関数を定義しました: アイテムの詳細を変更し、新しいアイテムを追加し、アイテムを削除します。 handleItemChange関数は、ユーザーがプロパティを変更した場合にアイテムのプロパティを更新します。 addItem 関数は、リストに新しいアイテムを追加します。deleteItem 関数は、アイテムをリストから削除します。 const handleItemChange = (index, event) => { let newItems = [...items]; newItems[index][event.target.name] = event.target.value; setItems(newItems); }; const addItem = () => { setItems([...items, { name: "", quantity: "", price: "" }]); }; const deleteItem = (index) => { let newItems = [...items]; newItems.splice(index, 1); setItems(newItems); }; const handleItemChange = (index, event) => { let newItems = [...items]; newItems[index][event.target.name] = event.target.value; setItems(newItems); }; const addItem = () => { setItems([...items, { name: "", quantity: "", price: "" }]); }; const deleteItem = (index) => { let newItems = [...items]; newItems.splice(index, 1); setItems(newItems); }; JAVASCRIPT インボイスの生成 次に示すのは、generateInvoice 関数のコードです。 // Generate invoice const generateInvoice = () => { // Validate the input fields if ( !customerName || !customerAddress || items.some((item) => !item.name || !item.quantity || !item.price) ) { setError(true); return; } // Create a new jsPDF instance let doc = new jsPDF("p", "pt"); // Add invoice header doc.setFontSize(24); doc.text("Invoice", 40, 60); doc.setFontSize(10); doc.text("Invoice Number: 123456", 40, 90); doc.text("Date: " + new Date().toDateString(), 40, 110); doc.text(`Customer Name: ${customerName}`, 40, 130); doc.text(`Customer Address: ${customerAddress}`, 40, 150); // Add items section doc.setFontSize(14); doc.text("Items:", 40, 200); doc.line(40, 210, 550, 210); // Add item details doc.setFontSize(12); let yOffset = 240; let total = 0; items.forEach((item) => { let itemTotal = item.quantity * item.price; total += itemTotal; doc.text(`Item: ${item.name}`, 40, yOffset); doc.text(`Quantity: ${item.quantity}`, 200, yOffset); doc.text(`Price: $${item.price}`, 300, yOffset); doc.text(`Total: $${itemTotal}`, 400, yOffset); yOffset += 20; }); // Add total doc.line(40, yOffset, 550, yOffset); doc.setFontSize(14); doc.text(`Total: $${total}`, 400, yOffset + 30); // Save the generated PDF as "invoice.pdf" doc.save("invoice.pdf"); // Reset error state setError(false); }; // Generate invoice const generateInvoice = () => { // Validate the input fields if ( !customerName || !customerAddress || items.some((item) => !item.name || !item.quantity || !item.price) ) { setError(true); return; } // Create a new jsPDF instance let doc = new jsPDF("p", "pt"); // Add invoice header doc.setFontSize(24); doc.text("Invoice", 40, 60); doc.setFontSize(10); doc.text("Invoice Number: 123456", 40, 90); doc.text("Date: " + new Date().toDateString(), 40, 110); doc.text(`Customer Name: ${customerName}`, 40, 130); doc.text(`Customer Address: ${customerAddress}`, 40, 150); // Add items section doc.setFontSize(14); doc.text("Items:", 40, 200); doc.line(40, 210, 550, 210); // Add item details doc.setFontSize(12); let yOffset = 240; let total = 0; items.forEach((item) => { let itemTotal = item.quantity * item.price; total += itemTotal; doc.text(`Item: ${item.name}`, 40, yOffset); doc.text(`Quantity: ${item.quantity}`, 200, yOffset); doc.text(`Price: $${item.price}`, 300, yOffset); doc.text(`Total: $${itemTotal}`, 400, yOffset); yOffset += 20; }); // Add total doc.line(40, yOffset, 550, yOffset); doc.setFontSize(14); doc.text(`Total: $${total}`, 400, yOffset + 30); // Save the generated PDF as "invoice.pdf" doc.save("invoice.pdf"); // Reset error state setError(false); }; JAVASCRIPT generateInvoice 関数では、まず入力フィールドの検証を実行し、顧客名、顧客住所、およびアイテムの詳細が入力されていることを確認します。 これらのフィールドのいずれかが空の場合は、error 状態を true に設定して早期に返します。 次に、new jsPDF("p", "pt") を呼び出して jsPDF の新しいインスタンスを作成します。 最初の引数 "p" はページの向きを縦方向、2 番目の引数 "pt" は測定単位をポイントとして指定します。 次に、PDF ドキュメントにコンテンツを追加し始めます。 doc.setFontSize を使用してフォントサイズを設定し、doc.text メソッドを使用してページの特定の座標にテキストを追加します。 インボイスのヘッダーに、タイトル、インボイス番号、日付、顧客名、顧客住所を追加します。 ヘッダーの後、フォントサイズを設定し、doc.line を使用してヘッダーからアイテムを分離する線を追加することにより、"アイテム" セクションを追加します。 次に、items 配列内の各アイテムを反復処理し、数量に価格を掛けて各アイテムの合計価格を計算します。total 変数をすべてのアイテム合計の合計で更新します。 各アイテムについて、doc.text を使用してアイテムの名前、数量、価格、およびアイテム合計を PDF ドキュメントに追加します。 各アイテムの次の行に移動するために、yOffset 変数をインクリメントします。 最後に、アイテムを合計から分離する線を追加し、doc.text を使用してドキュメントの右下に合計金額を追加します。 コンテンツが追加されたら、doc.save("invoice.pdf") を使用して、生成された PDF をユーザーのコンピュータに "invoice.pdf" として保存します。 最後に、以前のバリデーション エラーをクリアするために、error 状態を false にリセットします。 ステップ 4: UI のレンダリング return ステートメントには、レンダリングプロセスを処理する JSX コードが含まれています。 これには、顧客名と住所の入力フィールド、アイテムの詳細を入力するためのテーブル、アイテムを追加してインボイスを生成するためのボタン、およびバリデーションエラーを表示するためのエラースナックバーが含まれています。 ボタン、テキストフィールド、ボックス、コンテナ、タイポグラフィ、テーブル、テーブルボディ、テーブルセル、テーブルコンテナ、テーブルヘッド、テーブル行、紙、アイコンボタン、スナックバー、アラートとしてのMaterial-UIライブラリのコンポーネントを使用して、基本コンポーネントを作成します。 これらのコンポーネントは、フォームフィールド、テーブル、ボタン、およびエラーメッセージを作成するために使用されます。 return ( <Container maxWidth="md"> <Box sx={{ my: 4 }}> <Typography variant="h3" component="h1" gutterBottom> Create Invoice </Typography> {/* Customer Name and Address fields */} <Grid container spacing={3}> <Grid item xs={6}> <TextField label="Customer Name" fullWidth margin="normal" value={customerName} onChange={(e) => setCustomerName(e.target.value)} /> </Grid> <Grid item xs={6}> <TextField label="Customer Address" fullWidth margin="normal" value={customerAddress} onChange={(e) => setCustomerAddress(e.target.value)} /> </Grid> </Grid> {/* Items table */} <TableContainer component={Paper}> <Table sx={{ minWidth: 700 }} aria-label="invoice table"> <TableHead> <TableRow> <StyledTableCell>Item Name</StyledTableCell> <StyledTableCell align="left">Quantity</StyledTableCell> <StyledTableCell align="left">Price</StyledTableCell> <StyledTableCell align="left">Action</StyledTableCell> </TableRow> </TableHead> <TableBody> {items.map((item, index) => ( <StyledTableRow key={index}> <StyledTableCell component="th" scope="row"> <TextField fullWidth value={item.name} onChange={(event) => handleItemChange(index, event)} name="name" /> </StyledTableCell> <StyledTableCell align="right"> <TextField fullWidth value={item.quantity} onChange={(event) => handleItemChange(index, event)} name="quantity" /> </StyledTableCell> <StyledTableCell align="right"> <TextField fullWidth value={item.price} onChange={(event) => handleItemChange(index, event)} name="price" /> </StyledTableCell> <StyledTableCell align="right"> <IconButton onClick={() => deleteItem(index)}> <DeleteIcon /> </IconButton> </StyledTableCell> </StyledTableRow> ))} </TableBody> </Table> </TableContainer> {/* Buttons */} <Box mt={2} display="flex" gap={2}> <Button variant="contained" onClick={addItem}> Add Item </Button> <Button variant="outlined" color="success" onClick={generateInvoice}> Generate Invoice </Button> </Box> </Box> {/* Error Snackbar */} <Snackbar open={error} autoHideDuration={6000} onClose={() => setError(false)} anchorOrigin={{ vertical: "top", horizontal: "right" }} > <Alert onClose={() => setError(false)} severity="error"> Please fill in all required fields. </Alert> </Snackbar> </Container> ); return ( <Container maxWidth="md"> <Box sx={{ my: 4 }}> <Typography variant="h3" component="h1" gutterBottom> Create Invoice </Typography> {/* Customer Name and Address fields */} <Grid container spacing={3}> <Grid item xs={6}> <TextField label="Customer Name" fullWidth margin="normal" value={customerName} onChange={(e) => setCustomerName(e.target.value)} /> </Grid> <Grid item xs={6}> <TextField label="Customer Address" fullWidth margin="normal" value={customerAddress} onChange={(e) => setCustomerAddress(e.target.value)} /> </Grid> </Grid> {/* Items table */} <TableContainer component={Paper}> <Table sx={{ minWidth: 700 }} aria-label="invoice table"> <TableHead> <TableRow> <StyledTableCell>Item Name</StyledTableCell> <StyledTableCell align="left">Quantity</StyledTableCell> <StyledTableCell align="left">Price</StyledTableCell> <StyledTableCell align="left">Action</StyledTableCell> </TableRow> </TableHead> <TableBody> {items.map((item, index) => ( <StyledTableRow key={index}> <StyledTableCell component="th" scope="row"> <TextField fullWidth value={item.name} onChange={(event) => handleItemChange(index, event)} name="name" /> </StyledTableCell> <StyledTableCell align="right"> <TextField fullWidth value={item.quantity} onChange={(event) => handleItemChange(index, event)} name="quantity" /> </StyledTableCell> <StyledTableCell align="right"> <TextField fullWidth value={item.price} onChange={(event) => handleItemChange(index, event)} name="price" /> </StyledTableCell> <StyledTableCell align="right"> <IconButton onClick={() => deleteItem(index)}> <DeleteIcon /> </IconButton> </StyledTableCell> </StyledTableRow> ))} </TableBody> </Table> </TableContainer> {/* Buttons */} <Box mt={2} display="flex" gap={2}> <Button variant="contained" onClick={addItem}> Add Item </Button> <Button variant="outlined" color="success" onClick={generateInvoice}> Generate Invoice </Button> </Box> </Box> {/* Error Snackbar */} <Snackbar open={error} autoHideDuration={6000} onClose={() => setError(false)} anchorOrigin={{ vertical: "top", horizontal: "right" }} > <Alert onClose={() => setError(false)} severity="error"> Please fill in all required fields. </Alert> </Snackbar> </Container> ); JAVASCRIPT 完全な App.js および App.css コード ここにプロジェクトにコピーして貼り付けることができる完全な App.js コードがあります。 import React, { useState } from "react"; import "./App.css"; import { Button, TextField, Box, Container, Typography, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Paper, IconButton, Snackbar, Alert, } from "@mui/material"; import Grid from "@mui/material/Grid"; import DeleteIcon from "@mui/icons-material/Delete"; import jsPDF from "jspdf"; import { styled } from "@mui/material/styles"; import { tableCellClasses } from "@mui/material/TableCell"; const StyledTableCell = styled(TableCell)(({ theme }) => ({ [`&.${tableCellClasses.head}`]: { backgroundColor: theme.palette.common.black, color: theme.palette.common.white, }, [`&.${tableCellClasses.body}`]: { fontSize: 14, }, })); const StyledTableRow = styled(TableRow)(({ theme }) => ({ "&:nth-of-type(odd)": { backgroundColor: theme.palette.action.hover, }, "&:last-child td, &:last-child th": { border: 0, }, })); function App() { // State variables const [customerName, setCustomerName] = useState(""); const [customerAddress, setCustomerAddress] = useState(""); const [items, setItems] = useState([{ name: "", quantity: "", price: "" }]); const [error, setError] = useState(false); // Event handler for item changes const handleItemChange = (index, event) => { let newItems = [...items]; newItems[index][event.target.name] = event.target.value; setItems(newItems); }; // Add new item to the list const addItem = () => { setItems([...items, { name: "", quantity: "", price: "" }]); }; // Delete an item from the list const deleteItem = (index) => { let newItems = [...items]; newItems.splice(index, 1); setItems(newItems); }; // Generate invoice const generateInvoice = () => { // Validate the input fields if ( !customerName || !customerAddress || items.some((item) => !item.name || !item.quantity || !item.price) ) { setError(true); return; } // Create a new jsPDF instance let doc = new jsPDF("p", "pt"); // Add invoice header doc.setFontSize(24); doc.text("Invoice", 40, 60); doc.setFontSize(10); doc.text("Invoice Number: 123456", 40, 90); doc.text("Date: " + new Date().toDateString(), 40, 110); doc.text(`Customer Name: ${customerName}`, 40, 130); doc.text(`Customer Address: ${customerAddress}`, 40, 150); // Add items section doc.setFontSize(14); doc.text("Items:", 40, 200); doc.line(40, 210, 550, 210); // Add item details doc.setFontSize(12); let yOffset = 240; let total = 0; items.forEach((item) => { let itemTotal = item.quantity * item.price; total += itemTotal; doc.text(`Item: ${item.name}`, 40, yOffset); doc.text(`Quantity: ${item.quantity}`, 200, yOffset); doc.text(`Price: $${item.price}`, 300, yOffset); doc.text(`Total: $${itemTotal}`, 400, yOffset); yOffset += 20; }); // Add total doc.line(40, yOffset, 550, yOffset); doc.setFontSize(14); doc.text(`Total: $${total}`, 400, yOffset + 30); // Save the generated PDF as "invoice.pdf" doc.save("invoice.pdf"); // Reset error state setError(false); }; return ( <Container maxWidth="md"> <Box sx={{ my: 4 }}> <Typography variant="h3" component="h1" gutterBottom> Create Invoice </Typography> {/* Customer Name and Address fields */} <Grid container spacing={3}> <Grid item xs={6}> <TextField label="Customer Name" fullWidth margin="normal" value={customerName} onChange={(e) => setCustomerName(e.target.value)} /> </Grid> <Grid item xs={6}> <TextField label="Customer Address" fullWidth margin="normal" value={customerAddress} onChange={(e) => setCustomerAddress(e.target.value)} /> </Grid> </Grid> {/* Items table */} <TableContainer component={Paper}> <Table sx={{ minWidth: 700 }} aria-label="invoice table"> <TableHead> <TableRow> <StyledTableCell>Item Name</StyledTableCell> <StyledTableCell align="left">Quantity</StyledTableCell> <StyledTableCell align="left">Price</StyledTableCell> <StyledTableCell align="left">Action</StyledTableCell> </TableRow> </TableHead> <TableBody> {items.map((item, index) => ( <StyledTableRow key={index}> <StyledTableCell component="th" scope="row"> <TextField fullWidth value={item.name} onChange={(event) => handleItemChange(index, event)} name="name" /> </StyledTableCell> <StyledTableCell align="right"> <TextField fullWidth value={item.quantity} onChange={(event) => handleItemChange(index, event)} name="quantity" /> </StyledTableCell> <StyledTableCell align="right"> <TextField fullWidth value={item.price} onChange={(event) => handleItemChange(index, event)} name="price" /> </StyledTableCell> <StyledTableCell align="right"> <IconButton onClick={() => deleteItem(index)}> <DeleteIcon /> </IconButton> </StyledTableCell> </StyledTableRow> ))} </TableBody> </Table> </TableContainer> {/* Buttons */} <Box mt={2} display="flex" gap={2}> <Button variant="contained" onClick={addItem}> Add Item </Button> <Button variant="outlined" color="success" onClick={generateInvoice}> Generate Invoice </Button> </Box> </Box> {/* Error Snackbar */} <Snackbar open={error} autoHideDuration={6000} onClose={() => setError(false)} anchorOrigin={{ vertical: "top", horizontal: "right" }} > <Alert onClose={() => setError(false)} severity="error"> Please fill in all required fields. </Alert> </Snackbar> </Container> ); } export default App; import React, { useState } from "react"; import "./App.css"; import { Button, TextField, Box, Container, Typography, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Paper, IconButton, Snackbar, Alert, } from "@mui/material"; import Grid from "@mui/material/Grid"; import DeleteIcon from "@mui/icons-material/Delete"; import jsPDF from "jspdf"; import { styled } from "@mui/material/styles"; import { tableCellClasses } from "@mui/material/TableCell"; const StyledTableCell = styled(TableCell)(({ theme }) => ({ [`&.${tableCellClasses.head}`]: { backgroundColor: theme.palette.common.black, color: theme.palette.common.white, }, [`&.${tableCellClasses.body}`]: { fontSize: 14, }, })); const StyledTableRow = styled(TableRow)(({ theme }) => ({ "&:nth-of-type(odd)": { backgroundColor: theme.palette.action.hover, }, "&:last-child td, &:last-child th": { border: 0, }, })); function App() { // State variables const [customerName, setCustomerName] = useState(""); const [customerAddress, setCustomerAddress] = useState(""); const [items, setItems] = useState([{ name: "", quantity: "", price: "" }]); const [error, setError] = useState(false); // Event handler for item changes const handleItemChange = (index, event) => { let newItems = [...items]; newItems[index][event.target.name] = event.target.value; setItems(newItems); }; // Add new item to the list const addItem = () => { setItems([...items, { name: "", quantity: "", price: "" }]); }; // Delete an item from the list const deleteItem = (index) => { let newItems = [...items]; newItems.splice(index, 1); setItems(newItems); }; // Generate invoice const generateInvoice = () => { // Validate the input fields if ( !customerName || !customerAddress || items.some((item) => !item.name || !item.quantity || !item.price) ) { setError(true); return; } // Create a new jsPDF instance let doc = new jsPDF("p", "pt"); // Add invoice header doc.setFontSize(24); doc.text("Invoice", 40, 60); doc.setFontSize(10); doc.text("Invoice Number: 123456", 40, 90); doc.text("Date: " + new Date().toDateString(), 40, 110); doc.text(`Customer Name: ${customerName}`, 40, 130); doc.text(`Customer Address: ${customerAddress}`, 40, 150); // Add items section doc.setFontSize(14); doc.text("Items:", 40, 200); doc.line(40, 210, 550, 210); // Add item details doc.setFontSize(12); let yOffset = 240; let total = 0; items.forEach((item) => { let itemTotal = item.quantity * item.price; total += itemTotal; doc.text(`Item: ${item.name}`, 40, yOffset); doc.text(`Quantity: ${item.quantity}`, 200, yOffset); doc.text(`Price: $${item.price}`, 300, yOffset); doc.text(`Total: $${itemTotal}`, 400, yOffset); yOffset += 20; }); // Add total doc.line(40, yOffset, 550, yOffset); doc.setFontSize(14); doc.text(`Total: $${total}`, 400, yOffset + 30); // Save the generated PDF as "invoice.pdf" doc.save("invoice.pdf"); // Reset error state setError(false); }; return ( <Container maxWidth="md"> <Box sx={{ my: 4 }}> <Typography variant="h3" component="h1" gutterBottom> Create Invoice </Typography> {/* Customer Name and Address fields */} <Grid container spacing={3}> <Grid item xs={6}> <TextField label="Customer Name" fullWidth margin="normal" value={customerName} onChange={(e) => setCustomerName(e.target.value)} /> </Grid> <Grid item xs={6}> <TextField label="Customer Address" fullWidth margin="normal" value={customerAddress} onChange={(e) => setCustomerAddress(e.target.value)} /> </Grid> </Grid> {/* Items table */} <TableContainer component={Paper}> <Table sx={{ minWidth: 700 }} aria-label="invoice table"> <TableHead> <TableRow> <StyledTableCell>Item Name</StyledTableCell> <StyledTableCell align="left">Quantity</StyledTableCell> <StyledTableCell align="left">Price</StyledTableCell> <StyledTableCell align="left">Action</StyledTableCell> </TableRow> </TableHead> <TableBody> {items.map((item, index) => ( <StyledTableRow key={index}> <StyledTableCell component="th" scope="row"> <TextField fullWidth value={item.name} onChange={(event) => handleItemChange(index, event)} name="name" /> </StyledTableCell> <StyledTableCell align="right"> <TextField fullWidth value={item.quantity} onChange={(event) => handleItemChange(index, event)} name="quantity" /> </StyledTableCell> <StyledTableCell align="right"> <TextField fullWidth value={item.price} onChange={(event) => handleItemChange(index, event)} name="price" /> </StyledTableCell> <StyledTableCell align="right"> <IconButton onClick={() => deleteItem(index)}> <DeleteIcon /> </IconButton> </StyledTableCell> </StyledTableRow> ))} </TableBody> </Table> </TableContainer> {/* Buttons */} <Box mt={2} display="flex" gap={2}> <Button variant="contained" onClick={addItem}> Add Item </Button> <Button variant="outlined" color="success" onClick={generateInvoice}> Generate Invoice </Button> </Box> </Box> {/* Error Snackbar */} <Snackbar open={error} autoHideDuration={6000} onClose={() => setError(false)} anchorOrigin={{ vertical: "top", horizontal: "right" }} > <Alert onClose={() => setError(false)} severity="error"> Please fill in all required fields. </Alert> </Snackbar> </Container> ); } export default App; JAVASCRIPT ここに App.css コードがあります。 @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;700&display=swap'); .App { text-align: center; } .App-logo { height: 40vmin; pointer-events: none; } @media (prefers-reduced-motion: no-preference) { .App-logo { animation: App-logo-spin infinite 20s linear; } } h1, h2, h3, h4, h5, h6 { font-weight: bold; /* This is the weight for bold in Poppins */ color: #FF6347; /* This is the color Tomato. Replace with your preferred color */ } body { font-family: 'Poppins', sans-serif; background-color: #E9F8F4; } .App-header { background-color: #282c34; min-height: 100vh; display: flex; flex-direction: column; align-items: center; justify-content: center; font-size: calc(10px + 2vmin); color: white; } .App-link { color: #61dafb; } @keyframes App-logo-spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } ステップ 5: アプリケーションのテスト PDF 生成機能をテストするには、端末で次のコマンドを実行します。 npm start npm start SHELL これにより、開発サーバーが開始され、ブラウザで http://localhost:3000 にアプリケーションを表示できます。 入力フィールドに顧客名、住所、アイテムの詳細を入力し、「Generate Invoice」ボタンをクリックします。 PDF ファイルはコンピュータにダウンロードされ、開いて生成された請求書のフルページ表示を確認できます。 "Generate Invoice" ボタンをクリックすると、PDF ファイルが生成されます。 空白のフィールドで PDF を生成しようとすると、右上隅にエラーメッセージが表示されます。 IronPDF - Node.js PDF ライブラリ IronPDF for Node.js は、正確性、使いやすさ、速度に優れた包括的な Node.js PDF ライブラリです。 HTML、URL、およびReactの画像から直接PDFを生成、編集、フォーマットするための広範な機能を提供します。 Windows、MacOS、Linux、Docker、AzureやAWSなどのクラウドプラットフォームを含むさまざまなプラットフォームをサポートしているため、IronPDFはクロスプラットフォームの互換性を保証します。 直観的なAPIを備えているため、開発者は迅速にPDF生成と操作をNode.jsプロジェクトに統合することができます。 IronPDF Node.js の注目すべき機能には、ピクセル単位のレンダリング、広範なフォーマットオプション、PDF のマージや分割、注釈の追加、PDF フォームの作成などの高度な編集機能が含まれます。 Here is an example of generating a PDF document from an HTML File, HTML String, and URL: import { PdfDocument } from "@ironsoftware/ironpdf"; (async () => { const pdfFromUrl = await PdfDocument.fromUrl("https://getbootstrap.com/"); await pdfFromUrl.saveAs("website.pdf"); const pdfFromHtmlFile = await PdfDocument.fromHtml("design.html"); await pdfFromHtmlFile.saveAs("markup.pdf"); const pdfFromHtmlString = await PdfDocument.fromHtml("<p>Hello World</p>"); await pdfFromHtmlString.saveAs("markup_with_assets.pdf"); })(); import { PdfDocument } from "@ironsoftware/ironpdf"; (async () => { const pdfFromUrl = await PdfDocument.fromUrl("https://getbootstrap.com/"); await pdfFromUrl.saveAs("website.pdf"); const pdfFromHtmlFile = await PdfDocument.fromHtml("design.html"); await pdfFromHtmlFile.saveAs("markup.pdf"); const pdfFromHtmlString = await PdfDocument.fromHtml("<p>Hello World</p>"); await pdfFromHtmlString.saveAs("markup_with_assets.pdf"); })(); JAVASCRIPT PDF に関連するタスクに関する詳細なコード例については、この IronPDF コード例のページをご覧ください。 結論 結論として、React アプリケーションでの PDF の作成は威圧的である必要はありません。 適切なツールと明確な理解があれば、美しい構造化された PDF ドキュメントを簡単に生成できます。 各自に強みと独自の機能を持つ、jsPDF、pdfmake、React-PDF など、さまざまなライブラリを調査しました。 IronPDF のフレームワーク用の簡単な統合プロセスとライブラリに関する素晴らしいドキュメント、そして応答性の高い技術サポートにより、開発者は迅速に立ち上げることができ、Node.js アプリケーションでプロフェッショナル品質の PDF を生成するための最適な選択です。 IronPDF では、その完全な機能の無料トライアルを提供しています。 It is also available for other languages like C# .NET, Java, and Python. IronPDFのウェブサイトにアクセスして、詳細をご覧ください。 Darrius Serrant 今すぐエンジニアリングチームとチャット フルスタックソフトウェアエンジニア(WebOps) Darrius Serrantは、マイアミ大学でコンピュータサイエンスの学士号を取得し、Iron SoftwareでフルスタックWebOpsマーケティングエンジニアとして働いています。若い頃からコーディングに惹かれ、コンピューティングを神秘的かつアクセス可能なものとし、創造性と問題解決のための完璧な媒体と考えていました。Iron Softwareでは、新しいものを創造することと、複雑なコンセプトをより理解しやすくすることを楽しんでいます。Resident Developerの一人として、次世代に専門知識を共有するために、学生を教えることにも志願しました。Darriusにとって、その仕事は価値があり、実際の影響があるため、満足感があります。 関連する記事 更新日 7月 28, 2025 JavaScript PDF エディタ(開発者向けチュートリアル) この詳細ガイドでは、IronPDF が提供する強力な機能を使用して、JavaScript PDF エディタを構築する複雑さを解き明かす旅に乗り出します。 詳しく読む 更新日 7月 28, 2025 JavaScript で PDF ファイルを作成する方法 IronPDF は開発者が PDF ドキュメントを生成、閲覧および編集することを容易にするために作成されました。それは強力な PDF 変換器として機能し、PDF ファイルを生成、編集、処理するためのベース API を提供します。 詳しく読む 更新日 7月 28, 2025 JavaScript で PDF ファイルを表示する方法 IronPDF は、HTML、HTML5、ASPX、Razor/MVC View など、さまざまなソースから PDF ファイルを生成することができます。HTML ページや画像を PDF ファイルに変換することが可能です。 詳しく読む JavaScript PDF エディタ(開発者向けチュートリアル)JavaScript で PDF ファイルを...
更新日 7月 28, 2025 JavaScript PDF エディタ(開発者向けチュートリアル) この詳細ガイドでは、IronPDF が提供する強力な機能を使用して、JavaScript PDF エディタを構築する複雑さを解き明かす旅に乗り出します。 詳しく読む
更新日 7月 28, 2025 JavaScript で PDF ファイルを作成する方法 IronPDF は開発者が PDF ドキュメントを生成、閲覧および編集することを容易にするために作成されました。それは強力な PDF 変換器として機能し、PDF ファイルを生成、編集、処理するためのベース API を提供します。 詳しく読む
更新日 7月 28, 2025 JavaScript で PDF ファイルを表示する方法 IronPDF は、HTML、HTML5、ASPX、Razor/MVC View など、さまざまなソースから PDF ファイルを生成することができます。HTML ページや画像を PDF ファイルに変換することが可能です。 詳しく読む