MatthewHerbst / react-to-print

Print React components in the browser. Supports Chrome, Safari, Firefox and EDGE
MIT License
2.06k stars 221 forks source link

How should i handle large data to print? #702

Closed AlejandroSanchez90 closed 5 months ago

AlejandroSanchez90 commented 5 months ago

So i have this task, i have to print a long array of users data, right now when the user go to profile, they see the print all button, and in that print button i have all the logic, but it does generate a printing template per user, that is hidden so its not rendered, this is only for printing, but i dont think this is good for performance, because if the user have like 40 or 50 pages to print, it will be a super long component, is the the only way of doing it ? or does react-to-print have something to manage this properly?

my second idea was to create like a modal, for preview of the pages to be printed, and then show another print button to cofirm, but this feels bad to me, as user should go directly to print when they click print

MatthewHerbst commented 5 months ago

Hey there. I'm not sure I fully understand your concern. Are you trying to avoid showing all the pages in the print preview window opened by the browser? I don't think that's possible to my knowledge, though it's generally pretty performant.

In terms of generating the content, you can pass a Promise to the onBeforeGetContent prop so that will cause react-to-print to wait to print until you resolve the promise, and during that time you can generate the temporary content for printing that may not display on the main page.

Does that answer your question?

AlejandroSanchez90 commented 5 months ago

Sorry you misunderstood me Right now we have a page where user can see all their "goals" we have a print button next to each goal, to single print, and a print all button, since we need a ref from a component that will be used to be printed, we have to render the component with display hidden, when the goals page load, but some user may have hundreds of goals, so my goal is just render the template just after the user click prints

On Fri, Mar 29, 2024, 12:42 PM Matthew Herbst @.***> wrote:

Hey there. I'm not sure I fully understand your concern. Are you trying to avoid showing all the pages in the print preview window opened by the browser? I don't think that's possible to my knowledge, though it's generally pretty performant.

In terms of generating the content, you can pass a Promise to the onBeforeGetContent prop so that will cause react-to-print to wait to print until you resolve the promise, and during that time you can generate the temporary content for printing that may not display on the main page.

Does that answer your question?

— Reply to this email directly, view it on GitHub https://github.com/MatthewHerbst/react-to-print/issues/702#issuecomment-2027537493, or unsubscribe https://github.com/notifications/unsubscribe-auth/A6NKLATCAKWVD53M4UIR3R3Y2WR2BAVCNFSM6AAAAABFOVG33OVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDAMRXGUZTONBZGM . You are receiving this because you authored the thread.Message ID: @.***>

MatthewHerbst commented 5 months ago

Ah. onBeforeGetContent is what you want I think. It would let you only render what you want to print when the print is happening, that way you don't need to have it rendered and hidden when not printing. Does that make sense?

AlejandroSanchez90 commented 5 months ago

Gonna try this on Monday, thanks you so much for the quick answer!

On Fri, Mar 29, 2024, 1:00 PM Matthew Herbst @.***> wrote:

Ah. onBeforeGetContent is what you want I think. It would let you only render what you want to print when the print is happening, that way you don't need to have it rendered and hidden when not printing. Does that make sense?

— Reply to this email directly, view it on GitHub https://github.com/MatthewHerbst/react-to-print/issues/702#issuecomment-2027553224, or unsubscribe https://github.com/notifications/unsubscribe-auth/A6NKLAQUDQYCIHK65EQTGLLY2WT2DAVCNFSM6AAAAABFOVG33OVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDAMRXGU2TGMRSGQ . You are receiving this because you authored the thread.Message ID: @.***>

AlejandroSanchez90 commented 5 months ago

Ah. onBeforeGetContent is what you want I think. It would let you only render what you want to print when the print is happening, that way you don't need to have it rendered and hidden when not printing. Does that make sense?

how would you use this? like you still needs to pass the ref to the content property right?

Edit: Is this how it's supposed to be used

function App() {
  const [print, setPrint] = useState(false);
  const printRef = useRef<HTMLDivElement | null>(null);
  return (
    <div>
      {print && <Template ref={printRef} />}
      <ReactToPrint
        trigger={() => <button>Print</button>}
        content={() => printRef.current}
        onBeforeGetContent={() => {
          setPrint(true);
          return Promise.resolve();
        }}
        onAfterPrint={() => {
          setPrint(false);
          return Promise.resolve();
        }}
      />
    </div>
  );
}
MatthewHerbst commented 5 months ago

That's basically right! Recall that setting state is async though, so it's a bit more complicated to know when the state has actually been set:

function App() {
  const [print, setPrint] = useState(false);
  const onBeforeGetContentResolveRef = useRef();
  const printRef = useRef<HTMLDivElement | null>(null);

  useEffect(() => {
    // Wait for the state update
    if (onBeforeGetContentResolveRef.current && print === true) {
      onBeforeGetContentResolveRef.current(); // Resolve the promise
      onBeforeGetContentResolveRef.current = undefined;
    }
  }, [print])

  return (
    <div>
      {print && <Template ref={printRef} />}
      <ReactToPrint
        trigger={() => <button>Print</button>}
        content={() => printRef.current}
        onBeforeGetContent={() => {
          setPrint(true);
          return new Promise((resolve) => {
            onBeforeGetContentResolveRef.current = resolve;
          });
        }}
        onAfterPrint={() => {
          setPrint(false);
        }}
      />
    </div>
  );
}

In the old world you could do this with the callback function from seState that runs after the state is applied, but they didn't add that into the functional component/hook world unfortunately

MatthewHerbst commented 5 months ago

@AlejandroSanchez90 circling back here, did the above work for you?

AlejandroSanchez90 commented 5 months ago

Hey Matthew, yup everything is good now thanks for the help!

On Fri, Apr 5, 2024, 1:58 PM Matthew Herbst @.***> wrote:

@AlejandroSanchez90 https://github.com/AlejandroSanchez90 circling back here, did the above work for you?

— Reply to this email directly, view it on GitHub https://github.com/MatthewHerbst/react-to-print/issues/702#issuecomment-2040452095, or unsubscribe https://github.com/notifications/unsubscribe-auth/A6NKLAVCIPBRQGOVYOJRYO3Y33X4PAVCNFSM6AAAAABFOVG33OVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDANBQGQ2TEMBZGU . You are receiving this because you were mentioned.Message ID: @.***>