透かしなしで本番環境でテストしてください。
必要な場所で動作します。
30日間、完全に機能する製品をご利用いただけます。
数分で稼働させることができます。
製品トライアル期間中にサポートエンジニアリングチームへの完全アクセス
ReactアプリケーションからPDFドキュメントを作成するチュートリアルへようこそ! このチュートリアルでは、さまざまなライブラリを使用してPDFを生成する方法を探り、人気のjsPDFライブラリを使用してReactコンポーネントから直接PDFファイルを作成する方法を学びます。 それでは、始めましょう!
PDF(ポータブル・ドキュメント・フォーマット)は、レイアウトや書式を保持したまま文書を共有および印刷するために広く使用されているファイル形式です。 Reactのウェブ開発者として、請求書、レポート、または販売契約書などのPDFドキュメントをReactアプリケーションから直接生成する必要があるシナリオに遭遇するかもしれません。
ReactアプリケーションでPDFドキュメントを作成することは、特にこの分野に不慣れな場合には困難な作業となります。 ありがたいことに、このプロセスを大幅に簡素化する複数のサードパーティライブラリが利用可能です。 それぞれのライブラリには独自の機能とユーティリティが備わっており、異なるユースケースに対応しています。 これらのライブラリについてもう少し詳しく見てみましょう。
jsPDFは、JavaScriptからPDFファイルを生成するために開発者の間で広く人気のあるライブラリです。 その主なセールスポイントの一つは、そのシンプルさです。 その構文と使用方法は非常に簡単で、HTMLコンテンツをすぐにPDFファイルに変換することができます。
PDFのフォーマットとレイアウトを制御することができ、フォントサイズや色の変更からページの向きやサイズの調整まで行えます。jsPDFは、ブラウザおよびサーバー環境の両方で機能する堅牢なソリューションであり、幅広いJavaScriptアプリケーションに適した優れた選択肢です。
pdfmakeは、純粋なJavaScriptで実装されたクライアント/サーバーサイドのPDF印刷ソリューションとして際立っています。 このライブラリは、総合的なAPIと柔軟なレイアウトオプションのおかげで、より複雑なPDFを作成するための優れた選択肢です。 pdfmakeを使用すると、シンプルなJavaScriptオブジェクトを使用してドキュメントの内容と構造を定義し、それを有効なPDFドキュメントに変換できます。
React-PDFは、Reactコンポーネントを使用してPDFファイルを作成するための強力な機能を提供するユニークなライブラリです。 JavaScriptオブジェクトでドキュメント構造を手動で作成する代わりに、再利用可能なコンポーネントとプロップを使用して、通常のReactアプリケーションを構築するのと同じようにPDFを作成できます。 IronPDFのウェブサイトには、React-PDFライブラリを使用してPDFを作成するチュートリアルがあります。
3つのライブラリすべてがReactでPDFドキュメントを生成するための強力なツールを提供しますが、このチュートリアルでは、シンプルさ、柔軟性、そしてコミュニティでの広範な採用によってjsPDFを使用します。 これは初心者にとっての参入障壁を低くし、またその堅牢な機能セットは多くのユースケースに適した選択肢となります。 以下のjsPDFの原則を探求することで、PDFを生成するための堅固な基盤が得られます。プロジェクトの要件に応じて、他のライブラリもより簡単に習得できるようになります。
このチュートリアルに進む前に、スムーズに進めるために必要なツールと知識を十分に備えていることを確認することが重要です。 このチュートリアルの前提条件は以下の通りです:
まず第一に、特にシングルページアプリケーションを構築するためのユーザーインターフェースを作成するためのポピュラーなJavaScriptライブラリであるReactについての基本的な理解を持っている必要があります。 Reactにおいて、JSX(JavaScript XML)、コンポーネント、状態、プロップスといった概念に精通しているべきです。
Reactアプリケーションを構築するための開発環境もコンピューター上にセットアップしておくべきです。 これは、テキストエディターまたは統合開発環境(IDE)を含みます。 Visual Studio Code、Atom、または Sublime Text といったテキストエディターはすべて良い選択肢です。
プロジェクトとその依存関係を管理するために、Node.jsとnpm(Node Package Manager)を使用します。 Node.jsがコンピューターにインストールされていることを確認してください。 Node.jsは、サーバー上でJavaScriptを実行できるJavaScriptランタイムです。 npmがインストールされているため、プロジェクトに必要なライブラリを管理できます。
以下のターミナルコマンドを実行して、Node.jsおよびnpmがインストールされているかどうかを確認できます:
node -v
npm -v
node -v
npm -v
これらのコマンドは、それぞれのシステムにインストールされているNode.jsとnpmのバージョンを表示します。 インストールされていない場合や、バージョンが古い場合は、Node.js の公式ダウンロードページから最新の長期サポート (LTS) バージョンをダウンロードしてインストールする必要があります。
それでは、Reactプロジェクトのセットアップを開始しましょう。 ターミナルを開き、プロジェクトを作成したいディレクトリに移動してください。 新しいReactアプリケーションを作成するには、次のコマンドを実行してください:
npx create-react-app pdf-from-react
npx create-react-app pdf-from-react
このコマンドは、基本的なReactプロジェクト構造を持つpdf-from-react
という新しいディレクトリを作成します。
次に、プロジェクトディレクトリに移動します:
cd pdf-from-react
cd pdf-from-react
では、私たちのコーディングエディタでプロジェクトを開き、実装を進めることができます。
まず、必要なパッケージをインストールする必要があります。 次のターミナルコマンドを使用して、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
まず、アプリケーションに必要な依存関係をインポートします。 これには、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";
jsx
当社のアプリに一貫したクロスブラウザの動作を追加するために、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,
},
}));
jsx
私たちのアプリケーションの主要なコンポーネントは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);
jsx
このコードブロックでは、ユーザーとの対話を処理するための関数を定義しました。具体的には、アイテムの詳細を変更する関数、新しいアイテムを追加する関数、およびアイテムを削除する関数です。 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);
};
jsx
次は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);
};
jsx
generateInvoice
関数では、まず入力フィールドの顧客名、顧客住所、および商品の詳細が記入されていることを確認するための検証を行います。 これらのフィールドのいずれかが空の場合、error
状態を true
に設定し、早期に返します。
次に、new jsPDF("p", "pt")
を呼び出して、新しいjsPDF
のインスタンスを作成します。 最初の引数「p
」はページの向きを縦に指定し、2番目の引数「pt
」は測定単位をポイントで指定します。
次に、PDFドキュメントにコンテンツを追加し始めます。 フォントサイズはdoc.setFontSize
によって設定し、doc.text
メソッドを使用してページ上の特定の座標にテキストを追加します。 請求書ヘッダーには、タイトル、請求書番号、日付、顧客名、および顧客住所を含めます。
ヘッダーの後に、「Items」セクションを追加します。フォントサイズを設定し、doc.line
を使用してアイテムをヘッダーから区切るためのラインを追加します。 次に、items
配列内の各アイテムを繰り返し、数量に価格を掛けて各アイテムの合計価格を計算します。そして、すべてのアイテムの合計の合計をtotal
変数で更新します。
各項目については、PDFドキュメントにアイテム名、数量、価格、およびアイテムの合計を追加するためにdoc.text
を使用します。 各アイテムに対して次の行に移動するためにyOffset
変数を増加させます。 最後に、項目と合計を区切るための線を追加し、doc.text
を使用してドキュメントの右下に合計金額を追加します。
コンテンツが追加されたら、doc.save("invoice.pdf")
を使用して、生成されたPDFをユーザーのコンピュータに「invoice.pdf」として保存します。 最後に、以前の検証エラーをクリアするためにerror
状態をfalse
にリセットします。
return
ステートメントには、レンダリングプロセスを処理するJSXコードが含まれています。 顧客名と住所の入力フィールド、アイテムの詳細を入力するためのテーブル、アイテムを追加するためのボタンと請求書を生成するためのボタン、そして検証エラーを表示するためのエラースナックバーが含まれています。
それは、基本的なコンポーネントを作成するために、Button
、TextField
、Box
、Container
、Typography
、Table
、TableBody
、TableCell
、TableContainer
、TableHead
、TableRow
、Paper
、IconButton
、Snackbar
、Alert
などの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>
);
jsx
以下は、プロジェクトにコピー&ペーストできる完全な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;
jsx
こちらが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);
}
}
PDF生成機能をテストするには、ターミナルで以下のコマンドを実行してください:
npm start
npm start
これにより開発サーバーが開始され、ブラウザでアプリケーションをhttp://localhost:3000
で表示できます。
入力フィールドに顧客名、住所、商品詳細を入力し、「請求書を生成」ボタンをクリックしてください。 PDFファイルはコンピューターにダウンロードされ、生成された請求書の全ページビューを開くことができます。
「請求書を生成」ボタンをクリックすると、PDFファイルが生成されます。
任意の空のフィールドでPDFを生成しようとすると、右上隅にエラーメッセージが表示されます。
IronPDF for Node.js は、正確性、使いやすさ、速度に優れた包括的なNode.js PDFライブラリです。 ReactでHTML、URL、および画像から直接PDFを生成、編集、およびフォーマットするための豊富な機能を提供します。 Windows、MacOS、Linux、Docker、AzureやAWSのようなクラウドプラットフォームを含む様々なプラットフォームをサポートすることで、IronPDFはクロスプラットフォームの互換性を保証します。 ユーザーフレンドリーなAPIにより、開発者はPDF生成および操作を迅速にNode.jsプロジェクトに統合することができます。
IronPDF Node.jsの特筆すべき機能には、ピクセルパーフェクトなレンダリング、豊富なフォーマットオプション、PDFのマージや分割、注釈の追加、PDFフォームの作成などの高度な編集機能が含まれます。
こちらは、HTMLファイル、HTML文字列、そしてURLから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");
})();
js
PDF関連のタスクに関するより多くのコード例については、このIronPDFコード例ページをご覧ください。
結論として、ReactアプリケーションでPDFを作成することは恐れる必要はありません。 適切なツールと明確な理解があれば、美しく構造化されたPDFドキュメントを簡単に生成することができます。 私たちは、jsPDF、pdfmake、React-PDFなどのさまざまなライブラリを調査しました。それぞれ異なる強みとユニークな機能を持っています。
IronPDFのJavaScriptフレームワークとライブラリへの統合プロセスは簡単で、優れたドキュメントと迅速な技術サポートがあるため、開発者はすぐに実行でき、Node.jsアプリケーションでプロフェッショナルグレードのPDFを生成するための最良の選択肢となります。
IronPDFは、その全機能の無料試用版を提供しています。 他の言語のためにも利用可能です、例えば C# .NET、Java、およびPython。 詳細については、IronPDFのウェブサイトをご覧ください。