I see in the documentation an example that calls from a functional component so I see the library has been updated with hooks but I'm curious if there is a current way to have the print component be a functional component as well.
The console error I receive is
"Refs are not available for stateless components. For "react-to-print" to work only Class based components can be printed "
so I guess this just isn't an option?
Not sure what you saw, but this library does not use hooks, which is the reason we cannot currently support functional components. To use hooks would require bumping the React peerDependency, which would be a breaking change.
Oh whoops I had misunderstood. Thanks for the response and very useful library!
@MatthewHerbst Are there plans to support functional components?
@vjsingh eventually. Doing so would require bumping our React peer dependency, which would be a breaking change. Since there's no use-case that I know of where someone can't use class based components at all, it's unlikely we'll bump that dependency anytime soon unless there is some other feature/bug that requires a breaking change.
@MatthewHerbst I see, that makes sense and seems like a good policy for the library. Good work!
For myself I created a new PrintableComponent which takes in a view (which can be a functional component), wraps it in a <View/> and then uses that as the component to pass to react-to-print. Seems to be working just fine and lets me use functional components.
@vjsingh Could you post example code of how you are setting up your PrintableComponent? I am trying to do this exact thing right now.
@AaronMinnamon Hope this helps
import * as React from 'react';
import { View } from 'react-native';
import ReactToPrint from 'react-to-print';
import PrintableGrid from 'src/web/Cards/PrintableGrid';
import RouteCard from 'src/web/Cards/RouteCard';
import Tile from 'src/web/Components/Tile';
interface InputProps {
displayView: JSX.Element;
PrintView: () => JSX.Element;
}
const PrintableComponent: React.FC<InputProps> = props => {
const componentRef = React.useRef();
return (
<>
<ReactToPrint
trigger={() => props.displayView}
content={() => componentRef.current}
/>
<View style={{ display: 'none' }}>
<View ref={componentRef}>
<props.PrintView/>
</View>
</View>
</>
);
}
export default PrintableComponent;
@vjsingh Perfect thank you!
Now if I could only figure out why my mobile styles are showing up in the print dialog window...
To add on @vjsingh 's answer.
Another trick is to pass a prop with the ref to the imported component.
Example:
Code in Print.js file:
import React, { useRef, Component } from 'react'
import ReactToPrint from 'react-to-print';
import Showprint from './showprint.js'
export default()=>{
const componentRef = useRef();
return (
<div>
<ReactToPrint
trigger={() => <a href="#">Print this out!</a>}
content={() => componentRef.current}
/>
<Showprint refPropWithAnotherName={componentRef} />
</div>
);
}
Code in showprint.js file:
import React,{Component} from 'react'
export default Showprint ({refPropWithAnotherName})=> {
return(
<div ref={refPropWithAnotherName}>
<p>hello</p>
</div>
);
}
WORKS LIKE MAGIC
Although @BossBele's solution seems to be good It seems only works with HTML elements and not react components, when you have a complex component or styled-component it is not able to pass the alert, my solution is to simply create a class-based HOC that renders a functional component
const Print = ({ okText, children, ...rest }) => {
const dashboardRef = useRef();
let nestChild = children;
let printButton = okText;
if (typeof children === "string") {
nestChild = <span>{children}</span>;
}
if (typeof okText === "string") {
printButton = <span>{okText}</span>;
}
return <>
<ReactToPrint
trigger={() => okText ? printButton :
<ButtonComponent className="a-btn--linkYellowBottom" text="despegar reporte" />}
content={() => dashboardRef.current}
documentTitle="example--document.pdf"
/>
<HOCView ref={dashboardRef}>
{React.cloneElement(nestChild, { ...rest })}
</HOCView>
</>;
};
class HOCView extends Component {
render() {
return <HOCViewStyle>
{this.props.children}
</HOCViewStyle>;
}
}
Print.propTypes = {
children: PropTypes.oneOfType([PropTypes.node, PropTypes.string]),
okText: PropTypes.oneOfType([PropTypes.node, PropTypes.string])
};
export default Print;
Styled HOC component, the component is hidden until print is launched in the browser
import styled from "styled-components";
export const HOCViewStyle = styled.div`
display: none;
@media print {
display: block;
}
`
the way it is used is as follows:
const App = () => {
return <div>
<Print>
<p>Render any children</p>
</Print>
</div>
}
The result is a button that will display the content (children) until it is pressed
Most helpful comment
@AaronMinnamon Hope this helps