Abhijeet
Abhijeet

Reputation: 95

React-to-Print Issue: Updated State not Reflected in Print Output

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

Answers (1)

Matthew Herbst
Matthew Herbst

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

Related Questions