This post was originally published on my Blog, check it out for more contents.
Introduction
I was working on a project recently and I got a unique(for me) requirement that needed me to generate pdf file from an array of values in the Browser, usually in my little experience in software development Pdf files are generated in the backend using Puppeteer for node js and FPDF for PHP e.t.c. So I had to look for a React library that could work for my use case, lucky for me I found React-pdf. I found other libraries like @progress/kendo-react-pdf but I decided to go with React-pdf because of its developer-friendly documentation.
The library was built by Diego Muracciole and also maintained by him.
So in the tutorial/ blog post, I will try to explain briefly how react-pdf works and also walk you through how to generate PDf from an array of objects coming from the Moviedb Api.
Features
While going through the documentation when I was trying to pick the appropriate library for my use-case there were some features of React-pdf that convinced me to use it, I will briefly talk about them:
Components
React-Pdf uses React-Primitives spec to create custom components that you can use to create and structure your PDF documents.
These components include:
- Document
- Page
- View
- Image
- Text
- Link
- Note
- Canvas
- PDFViewer
- PDFDownloadLink
- BlobProvider
You can checkout the docs for more details on what each component above does, Basically the components about help you create pdf using JSXesques syntax.
Styling
Now that we have an idea of how to create the PDF document how do we style it? React-pdf provides powerful styling solution using the StyleSheet API which helps you style your document using CSS, Media queries and Flexbox. Check the docs for the CSS properties they support.
What if you are a big fan of CSS-in-JS? well, they also support the entire styled-components API.
Fonts
React-Pdf has a Font API that helps you load fonts from different sources and use in your PDF document.
Those were some of the features that made me pick React-pdf. Also when I checked the Github Repository the maintainer Diego Muracciole is quite active and tries to respond to most issues opened.
Demo
So I will briefly work you through a simple example of generating pdf from the MoviesDB API. This demo is going to demonstrate generating the best movies of the year.
Folder Structure
project
β package.json
β
β
ββββPublic
β β 150.png
β β index.html
β β star.png
β
β
β
ββββsrc
β Movie.jsx
β MovieList.jsx
| constant.js
| index.js
| styles.css
index.js(entry)
import React from "react";
import ReactDOM from "react-dom";
import MovieList from "./MovieList";
import "./styles.css";
function App() {
return (
<div className="App">
<MovieList />
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
The index.js is the entry point of the application. It renders the <MovieList/> which is the parent component of our application.
MovieList.jsx
import React, { useState } from "react";
import Axios from "axios";
import { PDFDownloadLink } from "@react-pdf/renderer";
import { API_KEY } from "./constants";
import { PdfDocument } from "./Movie";
const years = [
{ value: "2010", text: "2010" },
{ value: "2011", text: "2011" },
{ value: "2012", text: "2012" },
{ value: "2013", text: "2013" },
{ value: "2014", text: "2014" },
{ value: "2015", text: "2015" },
{ value: "2016", text: "2016" },
{ value: "2017", text: "2017" },
{ value: "2018", text: "2018" },
{ value: "2019", text: "2019" }
];
export default function MovieList() {
const [year, setYear] = useState("");
const [movieDetails, setDetails] = useState([]);
const [show, setHide] = useState(false)
const fetchMovie = async e => {
setYear(e.target.value);
try {
let res = await Axios(
`https://api.themoviedb.org/3/discover/movie?api_key=${API_KEY}&primary_release_year=${year}&sort_by=vote_average.desc`
);
setDetails(res.data.results);
setHide(true)
} catch (error) {
console.log(error);
}
};
return (
<div className="container">
<h2>Best movies of the year</h2>
<label htmlFor="movies">Select Year</label>
<select id="movies" className="select" onChange={fetchMovie}>
<option defaultValue="" disabled>
Select your option
</option>
{years.map((year, index) => {
return (
<option key={index} value={year.value}>
{year.text}
</option>
);
})}
</select>
{show &&<PDFDownloadLink
document={<PdfDocument data={movieDetails} />}
fileName="movielist.pdf"
style={{
textDecoration: "none",
padding: "10px",
color: