-
-
Notifications
You must be signed in to change notification settings - Fork 223
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
3.0.0 upgrade help #742
Comments
Hi, same error on my side after upgrade to v3 : Before: const ficheToPrintRef = useRef(null);
const handlePrint = useReactToPrint({
content: () => ficheToPrintRef.current,
}); After my comprehension of the changelog: const ficheToPrintRef = useRef<HTMLDivElement>(null);
const handlePrint = useReactToPrint({ contentRef: ficheToPrintRef }); But when calling handlePrint I have this error too: "[
"\"react-to-print\" received a `contentRef` option and a optional-content param passed to its callback. The `contentRef` option will be ignored."
]" edit : lines where the error pop: function g(e2) {
const { contentRef: t2, fonts: o2, ignoreGlobalStyles: n2, onBeforePrint: r2, onPrintError: c2, preserveAfterPrint: d2, suppressErrors: u2 } = e2, p2 = (0, s.useCallback)((s2) => {
l(d2, true);
const p3 = function({ contentRef: e3, optionalContent: t3, suppressErrors: o3 }) {
return t3 ? (e3 && i({ level: "warning", messages: ['"react-to-print" received a `contentRef` option and a optional-content param passed to its callback. The `contentRef` option will be ignored.'] }), t3()) : e3 ? e3.current : void i({ messages: ['"react-to-print" did not receive a `contentRef` option or a optional-content param pass to its callback.'], suppressErrors: o3 });
}({ contentRef: t2, optionalContent: s2, suppressErrors: u2 });
if (!p3) return void i({ messages: ["There is nothing to print"], suppressErrors: u2 });
if (!p3) return void i({ messages: ['"react-to-print" could not locate the DOM node corresponding with the `content` prop'], suppressErrors: u2 });
const g2 = p3.cloneNode(true), f = document.querySelectorAll("link[rel~='stylesheet'], link[as='style']"), m = g2.querySelectorAll("img"), b = g2.querySelectorAll("video"), y = o2 ? o2.length : 0, v = (n2 ? 0 : f.length) + m.length + b.length + y, w = [], E = [], T = function() {
const e3 = document.createElement("iframe");
return e3.width = `${document.documentElement.clientWidth}px`, e3.height = `${document.documentElement.clientHeight}px`, e3.style.position = "absolute", e3.style.top = `-${document.documentElement.clientHeight + 100}px`, e3.style.left = `-${document.documentElement.clientWidth + 100}px`, e3.id = "printWindow", e3.srcdoc = "<!DOCTYPE html>", e3;
}(), A = (t3, o3) => {
w.includes(t3) ? i({ level: "debug", messages: ["Tried to mark a resource that has already been handled", t3], suppressErrors: u2 }) : (o3 ? (i({ messages: ['"react-to-print" was unable to load a resource but will continue attempting to print the page', ...o3], suppressErrors: u2 }), E.push(t3)) : w.push(t3), w.length + E.length === v && a(T, e2));
}, x = { contentNode: p3, clonedContentNode: g2, clonedImgNodes: m, clonedVideoNodes: b, numResourcesToLoad: v, originalCanvasNodes: p3.querySelectorAll("canvas") };
r2 ? r2().then(() => h(T, A, x, e2)).catch((e3) => {
null == c2 || c2("onBeforePrint", e3);
}) : h(T, A, x, e2);
}, [e2]);
return p2;
} |
Finally problem solved after seeing this issue : #724 My previous code was calling handlePrint directly: |
Thanks! My research didn't leed to this. But this leeds to a next question, I can't find how the documentTitle is now set. const handlePrint = useReactToPrint({
documentTitle: 'Title',
content: () => componentRef.current,
}); But if I am passing the ref like that, the console says nothing to print |
Try: const handlePrint = useReactToPrint({
documentTitle: 'Title',
contentRef: componentRef,
}); |
Hey folks, thanks for the messages, apologies if the upgrade process hasn't been smooth. Please feel free to continue posting in this thread and I'll answer/help as best I can. The core change as seen above is a new pattern for passing in the |
Hi guys, I am still getting the same error after upgrading to v3. I tried all the above solutions but none worked. Here's how my code looks like after update. import { Box, Flex, HStack } from '@chakra-ui/react';
import { BaseButton } from '@components/base/base-button';
import { useRef } from 'react';
import { useReactToPrint } from 'react-to-print';
import { TrayListTablePrint } from './tray-list-table-print';
interface TableActionProps {
onPrint?: () => void;
}
function TableActions({ onPrint }: TableActionProps) {
return (
<Flex direction='column'>
<Flex justifyContent='flex-end' mb={4}>
<HStack spacing='sm'>
<BaseButton size='sm' onClick={onPrint} colorScheme='green'>
Print
</BaseButton>
</HStack>
</Flex>
</Flex>
);
}
export function TrayListTable() {
const componentToPrintRef = useRef(null);
const handlePrint = useReactToPrint({
contentRef: componentToPrintRef
});
return (
<Box minH='100%' pos='relative'>
<TableActions
onPrint={handlePrint}
/>
<Box style={{ display: 'none' }}>
<TrayListTablePrint ref={componentToPrintRef} />
</Box>
</Box>
);
} |
@Idnan could you please be more specific about the error you are seeing? |
I see the source of confusion, I will push a doc update right now. @Idnan changing |
Thanks @MatthewHerbst for the quick help. I just tried and now it's giving me a new error TypeError: p.cloneNode is not a function |
I've published @Idnan the |
Thanks I will upgrade the package to v3.0.1 and test it. Regarding the |
I have figured out the issue with the Here's the old code. <Box style={{ display: 'none' }}>
<TrayListTablePrint ref={componentToPrintRef} columns={columnsToPrint} data={list} />
</Box> I think the issue was with the <Box style={{ display: 'none' }}>
<div ref={componentToPrintRef}>
<TrayListTablePrint columns={columnsToPrint} data={list} />
</div>
</Box> Thanks for the help @MatthewHerbst |
Glad you got it figured out! If your component is a functional component you'll need to wrap it in |
Hi! We tried to update to the latest version today and ran into an issue. Earlier, we used Now, we are trying to use We ran into two issues:
I understand that our setup is a bit special, but it worked like a charm in the previous version. Any pointers at all for how to make it work in version 3 would be greatly appreciated. I can also, of course, post some code or make a separate issue if that is better. |
Hey @hemm1 nice to hear from you again! I believe you should be able to solve your workflow by using the lazy print option we added in v2.15.0. Basically, you can now delay calling the callback from |
Thank you very much! This looks to be right up our alley. Most likely we should have been using Lazy print already, but we did not now it was added until now 😇 We will definitely try it out and get back to you 👌 |
Hi again! Me and my colleague tinkered a bit with this today, and we could not get the LazyContent to work for us either, unfortunately. The problem was the same, in that the Our problem is that the component we want to print does not exist (nor the data for it) when we click the button to print it. When we click the print button, we then first want to do a couple data calls, render the component and then finally print the component. We did manage to find a way to do it which seems to work perfectly, however. Instead of invoking A quick code example is in order: const [isPrinting, setIsPrinting] = useState(false);
const handlePrint = useReactToPrint({
onAfterPrint: () => setIsPrinting(false),
});
const callbackRef = useCallback(
(node: HTMLDivElement) => {
if (node !== null) handlePrint(() => node);
},
[handlePrint]
);
return (
<div className={c.link} onClick={() => setIsPrinting(true)}>
<div style={{ display: 'none' }}>
{isPrinting && (
<React.Suspense fallback={null}>
<PrintablePriceBoard id={car.id} salesForm={car.salesForm} ref={callbackRef} />
</React.Suspense>
)}
</div>
</div> Inside the We can't see any problems with this and are very happy with how it all turned out. 🎉 Thank you again for an awesome library and very attentive and helpful comments! 🙌 |
@hemm1 that looks great, thank you so much for sharing, callback ref makes perfect sense! I'll look into how to best update the README and examples to show this method |
Based on @hemm1 answer I came up with the following generic component interface Props {
images: () => Promise<Blob[]>;
printing: boolean;
setPrinting: React.Dispatch<React.SetStateAction<boolean>>;
}
export const PrintableImages: React.FC<Props> = ({images, printing, setPrinting}: Props) => {
const [printImagesUrls, setPrintImagesUrls] = useState<string[]>([]);
const printFn = useReactToPrint({
onAfterPrint: () => {
setPrintImagesUrls(prev => {
prev.forEach((url: string) => {
URL.revokeObjectURL(url);
});
return [];
});
setPrinting(false);
},
});
const printRef = useCallback(
(node: HTMLDivElement | null) => {
if (node) {
printFn(() => node);
}
},
[printFn]
);
useEffect(() => {
if (!printing) {
return;
}
void (async () => {
const urls: string[] = (await images).map((blob: Blob): string => URL.createObjectURL(blob));
setPrintImagesUrls(urls);
})();
}, [image, printing]);
return (
<div style={{display: 'none'}}>
{!!printImagesUrls.length && (
<div ref={printRef}>
{printImagesUrls.map((url: string, i: number) => (
<img key={i} src={url} style={{breakAfter: 'always'}} />
))}
</div>
)}
</div>
);
}; Example usage: const [isPrinting, setIsPrinting] = useState<boolean>(false);
//...
<Button onClick={() => {setIsPrinting(true)}}>Print</Button>
<PrintableImages image={images} printing={isPrinting} setPrinting={setIsPrinting} /> |
I am unable to print, I using below code: I am getting "There is nothing to Print" error. Please suggest. function FormPrintWrapper(props) {
const parsed = Utility.parseQueryString(window.location.search);
let {engagementId, documentId, snapshotId, snapshotUser, snapshotDate} = props;
const isAutomatedPrint = parsed.isautomatedprint;
// The component was called from outside Kronos (ie: batch print). Get the parameters from the URL
if (isAutomatedPrint) {
engagementId = parsed.engagementid;
documentId = parsed.documentid;
snapshotId = parsed.snapshotid;
snapshotUser = parsed.snapshotuser;
snapshotDate = parsed.snapshotdate?.toUpperCase();
}
if (snapshotId === '-1') {
snapshotDate = moment().format('YYYY-MM-DDTHH:mm:ss');
}
const printViewRef = useRef(null);
const componentRef = useRef(null);
const [isRendered, setIsRendered] = useState(false);
const handlePrint = useReactToPrint({
contentRef: printViewRef.current
});
useEffect(() => {
if (isRendered) {
setTimeout(() => {
handlePrint();
}, 500);
}
}, [isRendered]);
function renderPrintViewContent() {
return (
<FormPrintViewContainer
setIsRendered={setIsRendered}
engagementId={engagementId}
documentId={documentId}
snapshotId={snapshotId}
snapshotUser={snapshotUser}
snapshotDate={snapshotDate}
/>
);
}
if (!isRendered) {
printViewRef.current = renderPrintViewContent();
}
return (
<StyledFormPrintWrapper ref={componentRef} className="StyledFormPrintWrapper">
{printViewRef.current}
</StyledFormPrintWrapper>
);
}
export default FormPrintWrapper; |
@gyanranjan89 pass the whole ref to // Before
const handlePrint = useReactToPrint({
contentRef: printViewRef.current
});
// After
const handlePrint = useReactToPrint({
contentRef: printViewRef
}); Your setup could also be significantly simplified if return (
<StyledFormPrintWrapper ref={componentRef} className="StyledFormPrintWrapper">
<FormPrintViewContainer
setIsRendered={setIsRendered}
engagementId={engagementId}
documentId={documentId}
ref={printViewRef}
snapshotId={snapshotId}
snapshotUser={snapshotUser}
snapshotDate={snapshotDate}
/>
</StyledFormPrintWrapper>
); |
You'll need to share some code please. Ideally if you could make a working codesandbox, that would be best |
This is mostly what I am trying to do: (I have to show the data on underlying page and also print) |
The way you have it right now, the ref value is the React component, not the underlying DOM node. Here is a modified version of your code working: https://codesandbox.io/p/sandbox/keen-meadow-tdzgkr?file=%2Fexamples%2FCustomPrint%2Findex.js%3A15%2C21 Notice that I used css to manage the print content displaying or not. There are other ways to do this with state and javascript, but the css option is by far the simplest. If you want the print content (data in your case) to always display, just remove the css class I added |
Thank you so much, making that change just worked. Earlier we had setup like that to print with previous version. |
Hi after updateing to 3.0.0 I get the error "t is not a function", even after breaking it down to your example:
I used chrome on windows.
Please forgive me if this is the wrong place or I am missing info, it's the first time for posting an issue ;)
The text was updated successfully, but these errors were encountered: