You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

react-to-print报错Argument appears to not be a ReactComponent

问题描述

使用react-to-print实现组件打印功能时,基础功能运行正常,按业务需求自定义组件后,触发打印抛出Argument appears to not be a ReactComponent. Keys:报错,常规检索未找到有效解决方案。
报错截图
现象:点击showcontent按钮可正常查看组件渲染内容,点击print按钮触发打印时抛出上述错误。

相关代码

待打印组件(ModalContent)

const  ModalContent=React.forwardRef(({ ticketDetails, bookingHistory, movie }, ref)=>{

    var op = movie.filter((e, i, arr) => {
        return e._id == bookingHistory.movieId
    })

    const [invoiceSummary, setinvoiceSummary] = useState({
        totalSeatCount: bookingHistory.seatSeletion.length,
        ticketPrice: op[0].ticketPrice,
        gstRate: op[0].gst,
        serviceCharge: op[0].serviceCharge
    })
   
    const [summaryFinalOk, setsummaryFinalOk] = useState(true);
    useImperativeHandle(ref, () => ({
        showTick() {
            setsummaryFinalOk(true);
        }
    }));
    return (<>

        <div className="card">
            {summaryFinalOk ?<>
                <svg class="checkmark" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 52 52">
                    <circle class="checkmark__circle" cx="26" cy="26" r="25" fill="none" />
                    <path class="checkmark__check" fill="none" d="M14.1 27.2l7.1 7.2 16.7-16.8" />
                </svg>
                 <h3>your Ticket has been Confirmed</h3></>
                 : <>
                    <div className="card-header bg-black"></div>
                    <div className="card-body">
                        <div className="row">
                           

                            <div className="row text-center">
                                <h3 className="text-uppercase text-center mt-3 invoice-h3" >Invoice</h3>
                            </div>

                            <div className="row mx-3">
                                <table className="table">
                                    <thead>
                                        <tr>
                                            <th scope="col">Ticket Order Summary </th>
                                            <th scope="col">Amount</th>
                                        </tr>
                                    </thead>
                                    <tbody>
                                        <tr>
                                            <td>Ticket price</td>
                                            <td>{invoiceSummary.totalSeatCount} x {invoiceSummary.ticketPrice} =  {invoiceSummary.totalSeatCount * invoiceSummary.ticketPrice}<i class="fa-solid fa-indian-rupee-sign"></i></td>
                                        </tr>
                                        <tr>
                                            <td>Gst</td>
                                            <td>{invoiceSummary.gstRate} % ={(invoiceSummary.totalSeatCount * invoiceSummary.ticketPrice) * invoiceSummary.gstRate / 100}<i class="fa-solid fa-indian-rupee-sign"></i></td>
                                        </tr>
                                        <tr>
                                            <td>Internet Handling</td>
                                            <td>{invoiceSummary.totalSeatCount} x{invoiceSummary.serviceCharge}={invoiceSummary.totalSeatCount * invoiceSummary.serviceCharge}<i class="fa-solid fa-indian-rupee-sign"></i></td>
                                        </tr>
                                    </tbody>
                                </table>
                            </div>
                            <hr></hr>
                          
                        </div>
                    </div>
                </>}
        </div>

    </>);
})

父组件(TicketBooking)

import React, { memo, useEffect, useState, useRef, useCallback } from 'react';
import  {useReactToPrint} from 'react-to-print';
import ModalContent from './modalContent';
function TicketBooking({ }) {
    const tick=useRef();
  

    //print the data
   

 const handlePrint = useReactToPrint({
        content: () => tick.current
      });
      const showcontent = ()=>{

      }
    
    return (
        <div className="container screen-design">
         <button onclick={showcontent}>showcontent</button>
                    <ModalContent ticketDetails={""} ref={tick} bookingHistory={[]} movie={""}></ModalContent>
                    <button onclick={handlePrint}>print</button>
        </div>)
}
export default memo(TicketBooking);
报错原因

报错核心是react-to-print没有拿到合法的可打印DOM节点,由两个核心问题共同导致:

  1. 待打印组件ModalContent最外层使用了React Fragment(<>...</>)作为根节点,Fragment不会生成真实DOM,ref无法直接绑定到实际渲染的DOM元素
  2. 使用useImperativeHandle自定义了ref暴露的内容,仅向外暴露了showTick方法,完全覆盖了默认的DOM节点引用,react-to-print拿到的ref值只有自定义方法,识别为非法的React组件
  3. 附加语法问题:React事件绑定使用了原生小写onclick,不符合React JSX语法规范,会导致按钮点击事件不生效
修复方案
  1. 移除ModalContent最外层的Fragment包裹,将需要打印的.card节点作为组件直接返回的根元素
  2. 在ModalContent内部单独创建ref绑定到打印根节点,通过useImperativeHandle同时向外暴露自定义方法和打印DOM节点
  3. 将JSX中的onclick事件修改为React标准驼峰写法onClick

修复后代码

ModalContent组件

const ModalContent = React.forwardRef(({ ticketDetails, bookingHistory, movie }, ref) => {
    // 单独创建ref绑定实际打印的DOM节点
    const printRootRef = useRef(null);

    var op = movie.filter((e, i, arr) => {
        return e._id == bookingHistory.movieId
    })

    const [invoiceSummary, setinvoiceSummary] = useState({
        totalSeatCount: bookingHistory.seatSeletion.length,
        ticketPrice: op[0].ticketPrice,
        gstRate: op[0].gst,
        serviceCharge: op[0].serviceCharge
    })
   
    const [summaryFinalOk, setsummaryFinalOk] = useState(true);
    useImperativeHandle(ref, () => ({
        // 保留原有自定义方法
        showTick() {
            setsummaryFinalOk(true);
        },
        // 额外暴露打印所需的DOM节点
        printElement: printRootRef.current
    }));

    // 移除最外层Fragment,直接返回根DOM节点并绑定内部ref
    return (
        <div className="card" ref={printRootRef}>
            {summaryFinalOk ? <>
                <svg class="checkmark" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 52 52">
                    <circle class="checkmark__circle" cx="26" cy="26" r="25" fill="none" />
                    <path class="checkmark__check" fill="none" d="M14.1 27.2l7.1 7.2 16.7-16.8" />
                </svg>
                 <h3>your Ticket has been Confirmed</h3></>
                 : <>
                    <div className="card-header bg-black"></div>
                    <div className="card-body">
                        <div className="row">
                            <div className="row text-center">
                                <h3 className="text-uppercase text-center mt-3 invoice-h3" >Invoice</h3>
                            </div>

                            <div className="row mx-3">
                                <table className="table">
                                    <thead>
                                        <tr>
                                            <th scope="col">Ticket Order Summary </th>
                                            <th scope="col">Amount</th>
                                        </tr>
                                    </thead>
                                    <tbody>
                                        <tr>
                                            <td>Ticket price</td>
                                            <td>{invoiceSummary.totalSeatCount} x {invoiceSummary.ticketPrice} =  {invoiceSummary.totalSeatCount * invoiceSummary.ticketPrice}<i class="fa-solid fa-indian-rupee-sign"></i></td>
                                        </tr>
                                        <tr>
                                            <td>Gst</td>
                                            <td>{invoiceSummary.gstRate} % ={(invoiceSummary.totalSeatCount * invoiceSummary.ticketPrice) * invoiceSummary.gstRate / 100}<i class="fa-solid fa-indian-rupee-sign"></i></td>
                                        </tr>
                                        <tr>
                                            <td>Internet Handling</td>
                                            <td>{invoiceSummary.totalSeatCount} x{invoiceSummary.serviceCharge}={invoiceSummary.totalSeatCount * invoiceSummary.serviceCharge}<i class="fa-solid fa-indian-rupee-sign"></i></td>
                                        </tr>
                                    </tbody>
                                </table>
                            </div>
                            <hr></hr>
                        </div>
                    </div>
                </>}
        </div>
    );
})

父组件TicketBooking

import React, { memo, useEffect, useState, useRef, useCallback } from 'react';
import  {useReactToPrint} from 'react-to-print';
import ModalContent from './modalContent';
function TicketBooking({ }) {
    const tick=useRef();

 const handlePrint = useReactToPrint({
        // 获取暴露的打印DOM节点
        content: () => tick.current.printElement
      });
      const showcontent = ()=>{
        // 调用子组件暴露的方法
        tick.current?.showTick()
      }
    
    return (
        <div className="container screen-design">
         {/* 修正事件名为驼峰写法 */}
         <button onClick={showcontent}>showcontent</button>
                    <ModalContent ticketDetails={""} ref={tick} bookingHistory={[]} movie={""}></ModalContent>
                    <button onClick={handlePrint}>print</button>
        </div>)
}
export default memo(TicketBooking);

额外提示:当前代码中传入ModalContent的bookingHistory初始为空数组、movie初始为空字符串,组件初始化阶段读取嵌套属性会触发报错,建议给props传入合法初始值,或使用可选链?.做安全取值处理。

内容的提问来源于stack exchange,提问作者shanmuga priya

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 08:12:24