react-to-print
react-to-print copied to clipboard
is it possible to print component without rendering it in the dom
I have this paginated table, i want to print the entire entries ( table without pagination ), while only the paginated table is in view...
You can use the onBeforeGetContent
callback to load the rest of the data into the component before printing:
const [data, setData] = useState(initialData);
const componentRef = useRef(null);
const onBeforeGetContentResolve = useRef(null);
useReactToPrint({
onBeforeGetContent = () => {
return new Promise((resolve) => {
fetchMyData.then((d) => {
setData(d);
onBeforeGetContentResolve = resolve;
});
});
},
onAfterPrint(() => {
setData(initialData); // Set `data` back to its pre-print value when printing is over
}),
});
useEffect(() => {
// Resolve the Promise once we know data has loaded into the state
if (onBeforeGetContentResolve.current && data.length > initialData.length) {
onBeforeGetContentResolve.current();
}
}, [data]);
return <div>{data.map(d) => <div key={d.id}>{d.value}</div>}</div>;
My implementation, creating a component that handles printing loading the component just before printing:
import { useRef, useEffect, useState } from 'react';
import ReactToPrint from 'react-to-print';
import PrintDownloadButton from 'components/PrintDownloadButton';
/**
* Print Component Without Loading Into View
* @param {object} props
* @param {JSX.Element} props.content
* @param {string} props.triggerLabel
* @returns {JSX.Element}
*/
export default function PrintAsync({
content,
triggerLabel,
}) {
const [isPrinting, setIsPrinting] = useState(false);
const [isStartedPrinting, setIsStartPrinting] = useState(false);
const printRef = useRef(null);
// We store the resolve Promise being used in `onBeforeGetContent` here
const promiseResolveRef = useRef(null);
// We watch for the state to change here, and for the Promise resolve to be available
useEffect(() => {
if (isPrinting && promiseResolveRef.current) {
// Resolves the Promise, letting `react-to-print` know that the DOM updates are completed
promiseResolveRef.current();
}
}, [isPrinting]);
return (
<>
<ReactToPrint
trigger={(buttonProps) => <PrintDownloadButton label={triggerLabel} {...buttonProps} />}
content={() => printRef.current}
onBeforeGetContent={() => {
setIsStartPrinting(true)
return new Promise((resolve) => {
promiseResolveRef.current = resolve;
setIsPrinting(true);
});
}}
onAfterPrint={() => {
// Reset the Promise resolve so we can print again
promiseResolveRef.current = null;
setIsPrinting(false);
setIsStartPrinting(false);
}}
bodyClass="p-4"
/>
<div style={{ display: 'none' }}>{isStartedPrinting ? content(printRef) : null}</div>
</>
);
}
Usage:
<PrintAsync
key="1"
triggerLabel="Print"
content={(ref) => (
<CustomComponent
ref={ref}
dynamicData={{}}
/>
)}
/>