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

React props传值异常:InvoicePDF渲染表格仅显示表头无行数据

问题原因

核心问题是条件渲染时生成了两个完全独立的FormDataTable组件实例,实例间内部状态完全不互通:

  • isInvoicevisible为true时渲染的FormDataTable,是你实际操作添加行数据的实例,所有录入的行数据都存在这个实例内部的tableData state中
  • 切换到isInvoicevisible为false时,你传给InvoicePDF的<FormDataTable />是全新挂载的独立实例,它的tableData初始值为空数组,也没有接收itemOpen、setitemOpen必要props,自然只能渲染出空表头,拿不到之前录入的行数据。

另外你原有代码里表格行的td顺序和表头th顺序不匹配,渲染后列会错位。

修复方案

方案1:提升状态到共同父组件(推荐)

把表格数据、行添加逻辑从FormDataTable内部上移到父组件NewInvoice中维护,作为唯一数据源分发给两个场景下的FormDataTable,从根源避免多实例状态不同步的问题。

  1. 修改NewInvoice组件代码,上移状态:
const NewInvoice = () => {
  const [isInvoicevisible, setisInvoicevisible] = useState(true);
  const [itemOpen, setitemOpen] = useState(false);
  // 原FormDataTable内的表格状态提升到父组件
  const [tableData, setTableData] = useState([]);

  // 行添加逻辑同步上移
  const addRows = (data) => {
    const totalData = tableData.length;
    data.id = totalData + 1;
    setTableData([...tableData, data]);
    setitemOpen(false);
  };

  return (
    <>
      {isInvoicevisible ? (
        <div>
          <FormDataTable
            itemOpen={itemOpen}
            setitemOpen={setitemOpen}
            tableData={tableData}
            addRows={addRows}
          />
        </div>
      ) : (
        <InvoicePDF
          childComponent={<FormDataTable tableData={tableData} itemOpen={false} />}
          address={address}
          fake={fake_logo}
          name={name}
          vat={Vat}
          subtotal={subtotal}
          invoiceDate={invoiceDate}
          invoiceNo={invoiceNo}
          discount={discount}
        />
      )}
    </>
  )
}
  1. 修改FormDataTable组件,移除内部状态,从props接收数据和方法,同时修正列顺序错位问题:
const FormDataTable = (props) => {
  const { itemOpen, tableData, addRows } = props;
  const [showForm, setshowForm] = useState(false);

  const tableRows = tableData.map((value, index) => {
    return (
      <tr key={index}>
        <td>{value.item}</td>
        <td>{value.description}</td>
        <td>{value.quantity}</td>
        <td>{value.rate}</td>
        <td>{value.amount}</td>
      </tr>
    );
  });

  return (
    <React.Fragment>
      <table className="table">
        <thead>
          <tr>
            <th>Item</th>
            <th>Description</th>
            <th>Qty</th>
            <th>Rate</th>
            <th>Amount</th>
          </tr>
        </thead>
        <tbody>{tableRows}</tbody>
      </table>
      {itemOpen && <AddItem show={itemOpen} func={addRows} />}
    </React.Fragment>
  )
}

InvoicePDF组件不需要修改,保持原有代码即可。

方案2:避免组件实例被销毁(快速修复)

如果不想调整状态位置,可以不用条件渲染销毁/重建组件,改用CSS的display属性控制两个视图的显示隐藏,保证FormDataTable始终是同一个实例,内部状态不会丢失:

// NewInvoice 组件内
// 先通过ref获取编辑态的FormDataTable实例
const tableRef = useRef(null);

return (
  <>
    <div style={{display: isInvoicevisible ? 'block' : 'none'}}>
      <FormDataTable
        ref={tableRef}
        itemOpen={itemOpen}
        setitemOpen={setitemOpen}
      />
    </div>
    <div style={{display: isInvoicevisible ? 'none' : 'block'}}>
      <InvoicePDF
        childComponent={tableRef.current}
        // 其余props保持不变
      />
    </div>
  </>
)

该方案可维护性较差,仅适合临时快速修复场景,优先选择状态提升的方案。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 17:16:17