React-pdf: Better examples to implement react-pdf, specifically downloading pdf or opening in browser

Created on 16 Mar 2019  路  3Comments  路  Source: diegomura/react-pdf

Is your feature request related to a problem? Please describe.
I am unable to figure out how to implement turning form or state data into a PDF using this package. The examples and documentation always come up just short enough that I cannot piece together what I really need.

Specifically, my problem is I would like a button that generates the pdf of a component. But, here is the recommended code from the doc:

import { PDFDownloadLink, Document, Page } from '@react-pdf/renderer'

const MyDoc = (
  <Document>
    <Page>
      // My document data
    </Page>
  </Document>
)

const App = () => (
  <div>
    <PDFDownloadLink document={MyDoc} fileName="somename.pdf">
      {({ blob, url, loading, error }) => (loading ? 'Loading document...' : 'Download now!')}
    </PDFDownloadLink>
  </div>
)

As a newbie coder, I'm having a really hard time understanding where blob comes from.

This attempt also doesn't help me.
https://andrewsempere.org/blog/2018/10/30/react-render-pdf.html

I would prefer to use HTML to render the PDF that I need, but my alternative is to measure pixel by pixel using jsPDF, which I will probably end up doing.

I noticed other people mention they have a hard time with the examples and documentation here.

If there is anyone who has successfully implemented this into their React app, please share the source code and any advice that you have.

Here is my App.jsx I am working on. I am using the component MyDocument as a test to put as data into the PDF generation, as well as trying to use PDFDownloadLink. What I am really trying to accomplish is to input data from the form into the state, and then generate the PDF using that new data. I'd like to view or download the pdf at the click of a button.

import React, { Component } from 'react'
import PDFDownloadLink, { Document, Page, View, Text, StyleSheet } from '@react-pdf/renderer';

// Create styles
const styles = StyleSheet.create({
  page: {
    flexDirection: 'row',
    backgroundColor: '#E4E4E4'
  },
  section: {
    margin: 10,
    padding: 10,
    flexGrow: 1
  }
});

// Create Document Component
const MyDocument = () => (
  <Document>
    <Page size="A4" style={styles.page}>
      <View style={styles.section}>
        <Text>Section #1</Text>
      </View>
      <View style={styles.section}>
        <Text>Section #2</Text>
      </View>
    </Page>
  </Document>
);

class App extends Component {

  onRender( blob ) {
    this.setState({ url: URL.createObjectURL(blob) });
  };

  constructor(props) {
    super(props)
    this.state = {
      lesson: '',
      title: '',
      author_name:'',
      author_email:'',
      grades:[],
      subjects:[],
      summary:'',
      steps:[],
      description:'',
      url: ''
    }

    this.updateText = this.updateText.bind(this)
    this.updateArray = this.updateArray.bind(this)
    this.addLessonStep = this.addLessonStep.bind(this)
    this.deleteLessonStep = this.deleteLessonStep.bind(this)
    this.updateStepText = this.updateStepText.bind(this)
    this.fileChangedHandler = this.fileChangedHandler.bind(this)
    this.onButtonPress = this.onButtonPress.bind(this)

  }

  updateText(e) {
    this.setState({
      [e.target.name]: e.target.value
    })
  }

  updateArray(e) {
    const list = this.state[e.target.name]

    if (e.target.checked) {
      this.setState({
        [e.target.name]: [...list, (e.target.value)]
      })
    } else {
      this.setState({
        [e.target.name]: list.filter(item => item !== e.target.value)
      })
    }
  }

  updateStepText(e, i) {
    const updatedStep = {
      ...this.state.steps[i],
      [e.target.name]: e.target.value
    }

    this.setState({
      steps: [
        ...this.state.steps.slice(0, i),
        updatedStep,
        ...this.state.steps.slice(i+1)
      ]
    })
  }

  addLessonStep() {
    const newStep = {
      'content':''
    }
    this.setState({
      steps: [...this.state.steps,
      newStep
      ]
    })
    console.log(this.state.steps)
  }

  deleteLessonStep(key) {
    const updatedStep = this.state.steps.filter((_,i)=>{
      return i !== key
    })
    this.setState({
      steps: updatedStep
    })
  }

  fileChangedHandler() {

  }

  onButtonPress() {
    const {title, author_name, author_email, grades, subjects, summary, steps } = this.state

  }


  render() {
    return (
      <div className="container-fluid h-100p mb-20">
      <header style={{margin:'50px'}}></header>
    <div className="row justify-content-center bg-white mb-20" style={{height:'inherit'}}>
      <div className="col-sm-6">
            <div><h1>PDF Generator Test</h1></div>
            <div>
              <h3 className="mb-10">
                Title
              </h3>
            </div>
            <div>
              <input type="text" className="b-1 b-gray h-55 w-100p mb-40" name="title" value={this.state.title} onChange={this.updateText} />
            </div>
            <div>
              <h3 className="mb-10">
                Author Name
              </h3>
            </div>
            <div>
              <input type="text" className="b-1 b-gray h-55 w-100p mb-40" name="author_name" value={this.state.author_name} onChange={this.updateText} />
            </div>
            <div>
              <h3 className="mb-10">
                Author Email
              </h3>
            </div>
            <div>
              <input type="text" className="b-1 b-gray h-55 w-100p mb-40" name="author_email" value={this.state.author_email} onChange={this.updateText} />
            </div>
              <div>
                <h3>
                  Subjects
                </h3>
              </div>
              <div className="mb-20">
                <span className="checkbox"><label className="pr-5" htmlFor="Art">Art</label><input type="checkbox" className="fl mb-20" name="subjects" value="Art" onChange={this.updateArray} id="Art"/></span>
                <span className="checkbox"><label className="pr-5" htmlFor="Astronomy">Astronomy</label><input type="checkbox" className="fl mb-20" name="subjects" value="Astronomy" onChange={this.updateArray} id="Astronomy"/></span>
                <span className="checkbox"><label className="pr-5" htmlFor="Chemistry">Chemistry</label><input type="checkbox" className="fl mb-20" name="subjects" value="Chemistry" onChange={this.updateArray} id="Chemistry"/></span>
                <span className="checkbox"><label className="pr-5" htmlFor="Computer Science">Computer Science</label><input type="checkbox" className="fl mb-20" name="subjects" value="Computer Science" onChange={this.updateArray} id="Computer Science"/></span>
                <span className="checkbox"><label className="pr-5" htmlFor="Engineering">Engineering</label><input type="checkbox" className="fl mb-20" name="subjects" value="Engineering" onChange={this.updateArray} id="Engineering"/></span>
                <span className="checkbox"><label className="pr-5" htmlFor="Games">Games</label><input type="checkbox" className="fl mb-20" name="subjects" value="Games" onChange={this.updateArray} id="Games"/></span>
                <span className="checkbox"><label className="pr-5" htmlFor="Language Arts">Language Arts</label><input type="checkbox" className="fl mb-20" name="subjects" value="Language Arts" onChange={this.updateArray} id="Language Arts"/></span>
                <span className="checkbox"><label className="pr-5" htmlFor="Math">Math</label><input type="checkbox" className="fl mb-20" name="subjects" value="Math" onChange={this.updateArray} id="Math"/></span>
                <span className="checkbox"><label className="pr-5" htmlFor="Music">Music</label><input type="checkbox" className="fl mb-20" name="subjects" value="Music" onChange={this.updateArray} id="Music"/></span>
                <span className="checkbox"><label className="pr-5" htmlFor="Physics">Physics</label><input type="checkbox" className="fl mb-20" name="subjects" value="Physics" onChange={this.updateArray} id="Physics"/></span>
                <span className="checkbox"><label className="pr-5" htmlFor="Science">Science</label><input type="checkbox" className="fl mb-20" name="subjects" value="Science" onChange={this.updateArray} id="Science"/></span>
                <span className="checkbox"><label className="pr-5" htmlFor="Social Studies">Social Studies</label><input type="checkbox" className="fl mb-20" name="subjects" value="Social Studies" onChange={this.updateArray} id="Social Studies"/></span>
                <span className="checkbox"><label className="pr-5" htmlFor="Statistics">Statistics</label><input type="checkbox" className="fl mb-20" name="subjects" value="Statistics" onChange={this.updateArray} id="Statistics"/></span>
               </div>
              <div className="mb-40">
                <h3>
                Grades
                </h3>
                <p className="sub-p mb-10">
                  (Choose grades as specifically as possible)
                </p>
              </div>
              <div>
                {[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13].map((grade) => <span key={grade} className="checkbox"><input type="checkbox" className="fl mb-20" name="grades" value={grade} onChange={this.updateArray} id={grade}/><label htmlFor={grade}>{grade}</label></span>)}
              </div>
              {this.state.steps.map((_, i) =>
                <div className="row" key={i}>
                  <div className="col-lg-4">
                    <div><p className="sub-p mb-10">Lesson Steps</p></div>
                  </div>
                  <div className="col-lg-8">
                    <div>
                      <input type="text" className="b-1 b-gray h-55 w-100p mb-40" className="b-1 b-gray h-45 w-100p mb-10" name="content" value={this.state.steps[i].content} onChange={(e) => this.updateStepText(e, i)} placeholder=""/>
                    </div>
                  </div>
                  <div className="b-1 b-gray mb-40">
                    <a className="delete" value={i} onClick={() => this.deleteLessonStep(i)}> x Delete this Attachment Entry</a>
                  </div>
                </div>
              )}
              <div className="mb-40">
                <a className="add" onClick={this.addLessonStep}>+ Add another step</a>
              </div>
              <div>
                <h3 className="mb-10">
                  Upload Attachment PDF
                </h3>
              </div>
              <div>
                <input type="file" className="b-1 b-gray h-55 mb-40" name="pdf" onChange={this.fileChangedHandler} />
              </div>
              <div>
                <PDFDownloadLink document={MyDocument} fileName="somename.pdf">
                  {({ blob, url, loading, error }) => (!loading ? 'Loading document...' : 'Download now!')}
                </PDFDownloadLink>
              </div>
            </div>
          <div className="col-sm-6">
            <div>
              <iframe type="application/pdf" src={this.state.lesson} width="640" height="480"/>
            </div>
          </div>
        </div>
        <div className="row" style={{margin:'20px', padding:'20px'}}></div>
            </div>
        )
    }
}
export default (App)

new feature

Most helpful comment

Further to @chemicalkosek's great example above, I recently wrote a blog on this that includes a codesandbox example:

https://medium.com/investing-in-tech/creating-api-driven-pdfs-on-the-fly-in-the-browser-using-react-react-pdf-and-typescript-78ab4d1e7da5

All 3 comments

Pass props into the MyDoc component. Modifying your code:

```import { PDFDownloadLink, Document, Page, Text } from '@react-pdf/renderer'

const MyDoc = (props) => (


// My document data
{props.formProps.author_name}


)

const DownloadLink = (props) => (


} fileName="somename.pdf">
{({ blob, url, loading, error }) => (loading ? 'Loading document...' : 'Download now!')}


)

Hope you get the idea... props.formData would be the props you pass from another component with form or something. You can pass even the whole state from another component like this 


```

Further to @chemicalkosek's great example above, I recently wrote a blog on this that includes a codesandbox example:

https://medium.com/investing-in-tech/creating-api-driven-pdfs-on-the-fly-in-the-browser-using-react-react-pdf-and-typescript-78ab4d1e7da5

Thank you @chemicalkosek and @pbrickles, these have been extremely helpful. The blog post is very well written and easy to follow 馃憦

Apologies for my frustration in the original post; I was starting to learn React on the job (馃槵) as a jr dev and so much was new. I understand it a lot more now that a few months have passed!

I'm going to write an article about what I've been able to create with an example on github that hopefully will address the confusion I had that might help others (using form data from a reducer or state, pagination, viewing in iframe (wrapper div needs height set to avoid iframe default height), downloading etc). Will share it at the end of the month or so.

Was this page helpful?
0 / 5 - 0 ratings