Reputation: 95
I am using react-to-print to print bills in my billing-system app. I've encountered an issue where one of the states (rows
), containing a list of bills, is updated just before printing to consolidate the items entered in the bill. Although the state is updated successfully, the print output does not reflect the changes.
MyComponent.jsx
const handleBillPrint = useReactToPrint({
content: () => printableRef.current,
onAfterPrint: () => handleBillSave("success") && handleBillReset(),
onBeforeGetContent: () => setRows(consolidateItemRows(rows))
})
I would appreciate any insights or solutions on why the updated state is not being reflected in the print output. Thank you!
Upvotes: 0
Views: 316
Reputation: 32043
Recall that state updates are asynchronous. This means that the setRows
call does not complete immediately. To fix this, you need to pass a Promise to onBeforeGetContent
and then detect that the rows have updated to finally resolve it. There is a README section (reproduced below) about this.
Setting state in
onBeforeGetContent
Recall that setting state is asynchronous. As such, you need to pass a Promise and wait for the state to update.const [isPrinting, setIsPrinting] = 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]); const handlePrint = useReactToPrint({ content: () => printRef.current, onBeforeGetContent: () => { return new Promise((resolve) => { promiseResolveRef.current = resolve; setIsPrinting(true); }); }, onAfterPrint: () => { // Reset the Promise resolve so we can print again promiseResolveRef.current = null; setIsPrinting(false); } });
Note: for Class components, just pass the resolve to the callback for
this.setState
:this.setState({ isPrinting: false }, resolve)
Upvotes: 1