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

React-to-Print问题:更新后的State未在打印输出中体现

React-To-Print 打印不更新合并后账单条目的问题解决

问题原因

React的state更新是异步批量处理的——你在onBeforeGetContent里调用setRows(consolidateItemRows(rows))后,rows不会立刻更新,组件也不会马上完成重渲染。此时printableRef.current指向的还是合并前的旧DOM结构,打印自然不会显示最新的合并结果。

解决方案

方案1:等待组件重渲染后再打印

利用onBeforeGetContent支持返回Promise的特性,等待state更新完成、组件重渲染后再继续打印流程:

import { useState, useEffect, useRef } from 'react';
import useReactToPrint from 'react-to-print';

const MyComponent = () => {
  const [rows, setRows] = useState(/* 初始账单数据 */);
  const [isPreparingPrint, setIsPreparingPrint] = useState(false);
  const printableRef = useRef();
  let resolvePrintPrepare;

  // 监听rows变化,当打印准备状态激活时,触发Promise完成
  useEffect(() => {
    if (isPreparingPrint) {
      resolvePrintPrepare?.();
      setIsPreparingPrint(false);
    }
  }, [rows, isPreparingPrint]);

  const handleBillPrint = useReactToPrint({
    content: () => printableRef.current,
    onAfterPrint: () => {
      handleBillSave("success");
      handleBillReset();
    },
    onBeforeGetContent: () => {
      // 更新为合并后的账单数据
      setRows(consolidateItemRows(rows));
      setIsPreparingPrint(true);
      // 返回Promise,等待重渲染完成
      return new Promise(resolve => {
        resolvePrintPrepare = resolve;
      });
    }
  });

  // 其他组件逻辑...
  return (
    <div>
      {/* 可打印区域 */}
      <div ref={printableRef}>
        {/* 账单列表渲染 */}
        {rows.map(row => <div key={row.id}>{row.name} × {row.quantity} = {row.amount}</div>)}
      </div>
      <button onClick={handleBillPrint}>打印账单</button>
    </div>
  );
};

方案2:直接使用合并后的数据打印,不依赖组件state

如果合并后的账单数据仅用于打印,不需要保留在组件state中,可以直接生成合并数据并传递给打印内容,绕开state异步更新的问题:

const MyComponent = () => {
  const [rows, setRows] = useState(/* 初始账单数据 */);
  const printableRef = useRef();

  const handleBillPrint = useReactToPrint({
    content: () => {
      // 直接生成合并后的账单数据
      const mergedRows = consolidateItemRows(rows);
      // 动态更新可打印区域的内容
      printableRef.current.innerHTML = mergedRows.map(row => 
        `<div key="${row.id}">${row.name} × ${row.quantity} = ${row.amount}</div>`
      ).join('');
      return printableRef.current;
    },
    onAfterPrint: () => {
      handleBillSave("success");
      handleBillReset();
      // 恢复原账单内容(如果需要)
      printableRef.current.innerHTML = rows.map(row => 
        `<div key="${row.id}">${row.name} × ${row.quantity} = ${row.amount}</div>`
      ).join('');
    }
  });

  return (
    <div>
      <div ref={printableRef}>
        {rows.map(row => <div key={row.id}>{row.name} × {row.quantity} = {row.amount}</div>)}
      </div>
      <button onClick={handleBillPrint}>打印账单</button>
    </div>
  );
};

方案3:拆分更新与打印步骤

先更新state,等组件重渲染完成后再手动触发打印:

const MyComponent = () => {
  const [rows, setRows] = useState(/* 初始账单数据 */);
  const [triggerPrint, setTriggerPrint] = useState(false);
  const printableRef = useRef();

  // 创建打印实例
  const printInstance = useReactToPrint({
    content: () => printableRef.current,
    onAfterPrint: () => {
      handleBillSave("success");
      handleBillReset();
      setTriggerPrint(false);
    }
  });

  // 监听打印触发状态,自动执行打印
  useEffect(() => {
    if (triggerPrint) {
      printInstance();
    }
  }, [triggerPrint, printInstance]);

  // 先更新数据,再触发打印
  const handleBillPrint = () => {
    setRows(consolidateItemRows(rows));
    // 等待组件重渲染后触发打印
    setTimeout(() => setTriggerPrint(true), 0);
  };

  return (
    <div>
      <div ref={printableRef}>
        {rows.map(row => <div key={row.id}>{row.name} × {row.quantity} = {row.amount}</div>)}
      </div>
      <button onClick={handleBillPrint}>打印账单</button>
    </div>
  );
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 12:55:57