IMMERHAZE
IMMERHAZE

Reputation: 71

Correct use of ReactToPrint?

The problem is that the button that is supposed to give the option to print is not working anymore.

the error in the console says:

To print a functional component ensure it is wrapped with `React.forwardRef`, and ensure the forwarded ref is used. See the README for an example: https://github.com/gregnb/react-to-print#examples

I Have already seen some solutions specifically talking about the same problem but I have not been able to make it work.

any suggestion?

this is the library i'm using: ReactToPrint npm

React To print


import { useRef } from "react";
import { useReactToPrint } from "react-to-print";
import Resume from "./Pdf/Pdf";

const  Example = () => {
  const componentRef = useRef();
  const handlePrint = useReactToPrint({
    content: () => componentRef.current
  });
  
  return (
    <div >
    <button onClick={handlePrint}>   ------> NOT WORKING!
      Descargar Pdf
    </button>
    <Resume ref={componentRef} />   ------> COMPONENT TO PRINT
  </div>
  );
};

export default Example;

Component to be printed



 import React from "react";
import styled from 'styled-components';
import PdfSection from './PdfSection';
import AlienLevel from './AlienLevel';
import {connect } from 'react-redux';

class Resume  extends React.Component {
  renderList = () => {
    return this.props.posts.diagnose.map((post) => {
      return (
        <PdfSection
          key={post.id}
          id={post.id}
          divider={"/images/pdf/divider.png"}
          img={"/images/alienRandom.png"}
          title={post.title}
          // data={post.data}
          text={post.text0}
          subtext={post.subtext0}
        />
      );
    });
  };

  render(){

  return (
    <div>
      <Container>
        <Page>
          <Portada>
            <img id="portada" src="/images/pdf/PortadaPdf.png" />
          </Portada>
        </Page>

        <Page>
          <AlienLevel
            result= "{props.diagn}{"
            character={"/images/pdf/alienMedio.png"}
            fileName={"responseBody[4].data"}
            level={"/images/pdf/level6.png"}
            correct={"/images/pdf/correct.png"}
            medium={"/images/pdf/medium.png"}
            incorrect={"/images/pdf/incorrect.png"}
            text='"Necesitas mejorar tus prácticas intergalácticas de CV, pero ya eres nivel medio!"'
          />
          <div>{this.renderList()}</div>
        </Page>
      </Container>
    </div>
  );
};
}
const mapStateToProps = (state) => {
  return { posts: state.posts };
};

export default connect(mapStateToProps)( Resume);

thanks in advance!

Upvotes: 1

Views: 16955

Answers (4)

Ram Chander
Ram Chander

Reputation: 1518

I was facing the same issue in functional components. I have resolved it myself as following.

import React, {useRef} from 'react';
import { useReactToPrint } from 'react-to-print';

import MainContentHeader from "./MainContentHeader";
import MainContentBody from "./MainContentBody";

function MainContent(_MUI){
    const componentRef = useRef();
    const handlePrint = useReactToPrint({
        content: ()=> componentRef.current
    })
    return <>
    <_MUI.Stack ref={componentRef} sx={{p:3}} direction="column" alignItems="center">
        <MainContentHeader 
            Grid={_MUI.Grid} 
            Stack={_MUI.Stack} 
            Button={_MUI.Button} 
            Typography={_MUI.Typography} 
            Box={_MUI.Box} />
        <MainContentBody  sx={{mt:2}} />
    </_MUI.Stack>
    <button onClick={handlePrint}>Print</button>
    </>
}
export default MainContent;

Upvotes: 0

Hik Hik
Hik Hik

Reputation: 41

I had the same issue and I am happy to share my findings as soon as now. The component has to be rendered somewhere using ref.

I added it to my page as hidden using React Material UI's Backdrop. Or u can hide it using hooks like examples below.

Using backdrop and only calling it when I need to preview the print. 👇👇

<Backdrop sx={{ color: "#fff", zIndex: (theme) => theme.zIndex.drawer + 1 }}
 open={openBD}>
   <ComponentToPrint ref={componentRef} />
</Backdrop>

Using Hooks plus display styling to only display it when needed. 👇👇

const [isReady, setIsReady] = useState("none");

<Paper style={{ display: isReady }} >
 <ComponentToPrint ref={componentRef} />
</Paper>

<Button
 variant="contained"
 endIcon={<BackupTableRoundedIcon />}
 onClick={() => setIsReady("")}
>
  Start Printing
 </Button>

Note: I used MUI components, if u decide to copy paste, then change Button to html <button and paper to <div. Hope this helps.

Upvotes: 0

IMMERHAZE
IMMERHAZE

Reputation: 71

For anyone that is struggling with the same error, it seems that they found the proper way to resolve this, I actually resolved it by following the Codesandbox I found in the Github issues here si the link. hope is useful! -->

LINK TO GITHUB SPECIFIC ISSUE (SOLVED!!)

Upvotes: 0

Shariq
Shariq

Reputation: 316

The problem is with connect() function of react-redux. You wrapped your component in connect and connect by default does not forward ref. Which means, the ref you are passing here <Resume ref={componentRef} /> does not reach to your component.

You need to pass options { forwardRef: true } in fourth parameter of connect function connect(mapStateToProps?, mapDispatchToProps?, mergeProps?, options?).

Just change this code export default connect(mapStateToProps)(Resume); in Resume component to this

export default connect(mapStateToProps, null, null, { forwardRef: true })(Resume);

Upvotes: 0

Related Questions