Dawn17
Dawn17

Reputation: 8297

How can we fetch a prop from the component that we are using? (React)

First of all, I am not using React-Redux. I know it would help, but it would take too long for my team to make a transition. So, please understand that I need a solution without React-Redux.

What I am trying to do is, I am building a PDF extractor. I want a user to select a page of a PDF that he/she wants to extract.

I have a component called PDFViewer which does the rendering work.

PDFViewer

 renderPdf() {
    const {pdf, pageNo} = this.state
    const container = document.getElementById('container')

    if(this.props.selectedPage){
      console.log('selectedPage exists', this.props.selectedPage)
      pdf.getPage(this.props.selectedPage).then((page) => {
        const scale = this.calcScale(page)
        const viewport = page.getViewport(scale)
        const div = document.createElement('div')

        // Set id attribute with page-#{pdf_page_number} format
        div.setAttribute('id', `page-${(page.pageIndex + 1)}`)
        div.style.width = `${viewport.width}px`
        div.style.height = `${viewport.height}px`
        page
          .getOperatorList()
          .then((opList) => {
            const svgGfx = new window.PDFJS.SVGGraphics(
              page.commonObjs,
              page.objs
            )

            return svgGfx.getSVG(opList, viewport)
          })
          .then((svg) => {
            // If there's already rendered page, delete it.
            if (container.childNodes.length > 0) {
              container.removeChild(container.childNodes[0])
            }
            container.appendChild(svg)
            return svg
          })
      })
    } else {

      console.log('props', this.props)

      pdf.getPage(pageNo).then((page) => {
        const scale = this.calcScale(page)
        const viewport = page.getViewport(scale)
        const div = document.createElement('div')

        // Set id attribute with page-#{pdf_page_number} format
        div.setAttribute('id', `page-${(page.pageIndex + 1)}`)
        div.style.width = `${viewport.width}px`
        div.style.height = `${viewport.height}px`
        page
          .getOperatorList()
          .then((opList) => {
            const svgGfx = new window.PDFJS.SVGGraphics(
              page.commonObjs,
              page.objs
            )

            return svgGfx.getSVG(opList, viewport)
          })
          .then((svg) => {
            // If there's already rendered page, delete it.
            if (container.childNodes.length > 0) {
              container.removeChild(container.childNodes[0])
            }
            container.appendChild(svg)
            return svg
          })
      })
    }
  }

  render() {
    const {pdf, pageNo} = this.state
    const {showPagination} = this.props

    return (
      <div>
        {showPagination && (
          <PageTurner
            nextPage={this.nextPage}
            previousPage={this.previousPage}
            pageNo={pageNo}
            numPages={pdf ? pdf.numPages : 0}
          />
        )}
        <div id="container" />
      </div>
    )

The PageTurner in render just makes the user selects the page that one wants to render. renderPdf() is in charge of rendering it.

NextComponent

render() {
    const tableStyle = this.getTableStyle();
    const tableSettings = this.getTableSettings();
    return (
        <div>
            {//<ReferenceMenu />
            }
            <div 
              style={sideBySide}>
            <PDFViewer
                paginationCallback={this.handlePageChange}
                pdfData={this.state.pdfData}
                desiredWidth={600}
                selectedPage={2}
            />
            <TablePosition
                style={tables}
                step={this.props.step}
                pdfData={this.props.pdfData}
                tableSettings={tableSettings}
                tableStyle={tableStyle}
                fileName={this.state.fileName}
                tableSize={this.getTableSize()}
                tableOffset={this.state.tableOffset}
                desiredWidth={700}
                updateXOffset={x => this.updateXOffset(x)}
                updateYOffset={y => this.updateYOffset(y)}
                markTable={() => this.markTable()}
                setOutputLabels={(row, col, val) => this.setOuputLabels(row, col, val)}
            />
            </div>
        </div>
    );
}

In my next component, it tries to render the page of the selected PDF page and align with the table that the PDF page has (the table part is not important in this question).

As you can see, I sent selectedPage={2} as a prop to the PDFViewer and this successfully renders the 2nd page of the PDF. But the value is hard coded.

My question is, how can I fetch the page number selected in PDFViewer (this.state.pageNo in PDFViewer) and use it in the selectedPage={ HERE } ?

Please help

Upvotes: 0

Views: 88

Answers (1)

Tyler
Tyler

Reputation: 2390

I took my simple example from the comments and substituted in your component names to give you a better idea of how to lift the state up the component tree. I tried to base the flow on what I could gather from the context of your problem. Again, I would recommend reading React's article Lifting State Up.

const PageTurner = ({ onConfirm, onPageChange, pageNo }) => (
  <div>
    <button type="button" onClick={() => onPageChange(pageNo - 1)}>
      Prev ({pageNo - 1})
    </button>
    <button type="button" onClick={() => onPageChange(pageNo + 1)}>
      Next ({pageNo + 1})
    </button>
    <button type="button" onClick={onConfirm}>
      Confirm
    </button>
  </div>
);

const PdfViewer = ({ pageNo }) => (
  <div>
    <h1>PdfViewer</h1>
    <h2>Current Page is {pageNo}</h2>
  </div>
);

const Step1 = ({ onConfirm, onPageChange, pageNo }) => (
  <div>
    <PdfViewer pageNo={pageNo} />
    <PageTurner
      onConfirm={onConfirm}
      onPageChange={onPageChange}
      pageNo={pageNo}
    />
  </div>
);

const NextComponent = ({ pageNo }) => (
  <div>
    <h1>NextComponent</h1>
    <label>Page number is {pageNo}</label>
  </div>
);
class App extends React.Component {
  constructor(props, context) {
    super(props, context);

    this.state = {
      pageNo: 1,
      step: 1
    };

    this.handleConfirm = this.handleConfirm.bind(this);
    this.handlePageChange = this.handlePageChange.bind(this);
  }

  handleConfirm() {
    this.setState({
      step: 2
    });
  }

  handlePageChange(pageNo) {
    this.setState(state => ({
      pageNo
    }));
  }

  render() {
    const { pageNo, step } = this.state;

    return (
      <div>
        {step === 1 && (
          <Step1
            onConfirm={this.handleConfirm}
            onPageChange={this.handlePageChange}
            pageNo={pageNo}
          />
        )}
        {step === 2 && <NextComponent pageNo={pageNo} />}
      </div>
    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

Upvotes: 1

Related Questions