๐Ÿ‘ฉ๐Ÿป‍๐Ÿ’ป Dev/Front-End (React)

react-to-print๋กœ A4 ์ถœ๋ ฅ ๋ ˆ์ด์•„์›ƒ ๋งŒ๋“ค๊ธฐ + useRef

yesolz 2025. 4. 9. 21:02
728x90

ํšŒ์‚ฌ ํ”„๋กœ์ ํŠธ์—์„œ ๊ฑฐ๋ž˜๋ช…์„ธํ‘œ๋ฅผ A4 ๊ฐ€๋กœ ๋ฐฉํ–ฅ(landscape)์œผ๋กœ ์ธ์‡„ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•ด์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค.

- ํ™”๋ฉด์—๋Š” ์™ผ์ชฝ ์˜์—ญ๋งŒ ํ‘œ์‹œ
- ์ธ์‡„ ์‹œ์—๋Š” A4 ํ•œ ์žฅ์„ ๊ฝ‰ ์ฑ„์›Œ ์ขŒ/์šฐ ๋ชจ๋‘ ์ถœ๋ ฅ (ํ•˜๋‚˜๋Š” ๊ณ ๊ฐ์šฉ / ํ•˜๋‚˜๋Š” ๋‚ด๋ถ€์šฉ)
- ์ธ์‡„ ์‹œ ์ „์šฉ ์Šคํƒ€์ผ ์ ์šฉ (ํฐํŠธ ํฌ๊ธฐ, ์—ฌ๋ฐฑ ๋“ฑ ์กฐ์ •)

์ด๋ฅผ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด React to Print์˜ useReactToPrint ํ›…์„ ์‚ฌ์šฉํ•˜์—ฌ, ํŠน์ • DOM์— ๋Œ€ํ•ด ์ธ์‡„ ์ž‘์—…์„ ์ง„ํ–‰ํ–ˆ์Šต๋‹ˆ๋‹ค.

 

์ด ๊ธ€์—์„œ๋Š” React to Print ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•ด ํŠน์ • ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ธ์‡„ํ•˜๊ณ , ์ธ์‡„ ์‹œ์—๋งŒ ์ ์šฉ๋˜๋Š” ์Šคํƒ€์ผ์„ ์„ค์ •ํ•˜์—ฌ ์ด ๋ฌธ์ œ๋ฅผ ์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ–ˆ๋Š”์ง€ ๊ณต์œ ํ•ด ๋ด…๋‹ˆ๋‹ค!

 

์™œ window.print()๊ฐ€ ์•„๋‹Œ React to Print?

์ผ๋ฐ˜์ ์œผ๋กœ ์›น์—์„œ ์ธ์‡„ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•  ๋•Œ window.print()๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฌธ์ œ์ ์ด ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.
1. ํŠน์ • ์ปดํฌ๋„ŒํŠธ๋งŒ ์ธ์‡„ํ•˜๊ธฐ ์–ด๋ ค์›€
window.print()๋Š” ๋ธŒ๋ผ์šฐ์ € ํ™”๋ฉด ์ „์ฒด๋ฅผ ์ธ์‡„ ๋Œ€์ƒ์œผ๋กœ ์žก์Šต๋‹ˆ๋‹ค. ํŠน์ • ๋ถ€๋ถ„(์ปดํฌ๋„ŒํŠธ)๋งŒ ์ธ์‡„ํ•˜๋ ค๋ฉด ๋ณ„๋„์˜ @media print ์ฒ˜๋ฆฌ, display: none ๋“ฑ ๋ณต์žกํ•œ ์„ค์ •์ด ํ•„์š”ํ•ด์ง‘๋‹ˆ๋‹ค.
2. ์ธ์‡„ ๋ฏธ๋ฆฌ๋ณด๊ธฐ๋‚˜ ์ž๋™ ๋‹ซ๊ธฐ ๋“ฑ ์„ธ๋ถ€ ์„ค์ • ๋ถˆ๊ฐ€
React ์ปดํฌ๋„ŒํŠธ ๋‹จ์œ„๋กœ ์ธ์‡„ ๊ณผ์ •์„ ์ œ์–ดํ•˜๊ธฐ๊ฐ€ ๊นŒ๋‹ค๋กญ์Šต๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž๊ฐ€ ์ธ์‡„ ๋Œ€์ƒ์„ ์†์‰ฝ๊ฒŒ ํ™•์ธํ•˜๊ณ , ์ถœ๋ ฅ ์ œ๋ชฉ ์„ค์ • ๋“ฑ์„ ํ•˜๋ ค๋ฉด ๋‹ค๋ฅธ ๋กœ์ง์„ ๋” ๊ตฌํ˜„ํ•ด์•ผ ํ•˜์ฃ .
3. ๋‹ค๋ฅธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€์˜ ํ˜ธํ™˜์„ฑ
์ธ์‡„ ์‹œ์ ์— DOM์„ ์ง์ ‘ ์กฐ์ž‘ํ•˜์ง€ ์•Š๊ณ , ๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ ๊ตฌ์กฐ์— ๋งž์ถฐ ์ธ์‡„๋ฅผ ๊ตฌํ˜„ํ•˜๋ ค๋ฉด React to Print ํ›…(useReactToPrint)์ด ํ›จ์”ฌ ๊ฐ„ํŽธํ•ฉ๋‹ˆ๋‹ค.

๊ฒฐ๊ณผ์ ์œผ๋กœ React to Print๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํŠน์ • ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋”ฐ๋กœ ๋ Œ๋”๋งํ•˜๊ณ , ๊ทธ ์˜์—ญ๋งŒ ์†์‰ฝ๊ฒŒ ์ธ์‡„ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ธ์‡„ ์Šคํƒ€์ผ์„ ์ปค์Šคํ„ฐ๋งˆ์ด์ง•ํ•˜๊ธฐ๊ฐ€ ์ˆ˜์›”ํ•ด์ง‘๋‹ˆ๋‹ค.

 

 

useRef์™€ React to Print์˜ ๋™์ž‘ ์›๋ฆฌ

  • useRef๋Š” React์—์„œ ํŠน์ • DOM ์š”์†Œ๋‚˜ ๊ฐ’์„ ์žฌ๋ Œ๋”๋ง ์—†์ด ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด ์ฃผ๋Š” ํ›…์ž…๋‹ˆ๋‹ค.
  • const printRef = useRef<HTMLDivElement | null>(null); ์ฒ˜๋Ÿผ ์„ ์–ธํ•ด ๋‘๊ณ , <div ref={printRef}>์— ์—ฐ๊ฒฐํ•˜๋ฉด, ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์žฌ๋ Œ๋”๋ง๋˜์–ด๋„ printRef.current๋Š” ๋ณ€ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • React to Print์˜ useReactToPrint ํ›…์€ content ์˜ต์…˜์œผ๋กœ ์ธ์‡„ํ•  DOM์„ ๋ฐ˜ํ™˜๋ฐ›์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๊ฐ€ content์— printRef.current๋ฅผ ๋„˜๊ธฐ๋ฉด, ํ•ด๋‹น DOM๋งŒ ๋ณ„๋„๋กœ ๋ธŒ๋ผ์šฐ์ €์˜ ์ธ์‡„ ๊ธฐ๋Šฅ์„ ํ†ตํ•ด ๋ฏธ๋ฆฌ๋ณด๊ธฐ·์ธ์‡„ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ pageStyle ์˜ต์…˜์„ ํ†ตํ•ด ์ธ์‡„ ์‹œ ์ „์šฉ ์Šคํƒ€์ผ์„ ์ถ”๊ฐ€๋กœ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

 

A4 ๊ฐ€๋กœ ๋ฐฉํ–ฅ ์ธ์‡„ ๋ ˆ์ด์•„์›ƒ ์žก๊ธฐ

์ธ์‡„ ์˜์—ญ(printRef)์— ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋‘ ๊ฐœ์˜ ์˜์—ญ์„ ๋ฐฐ์น˜ํ•ฉ๋‹ˆ๋‹ค.
• ์™ผ์ชฝ ์˜์—ญ: ํ™”๋ฉด์—๋„ ๋ณด์ด๊ฒŒ ํ•จ
• ์˜ค๋ฅธ์ชฝ ์˜์—ญ: ํ™”๋ฉด์—์„œ๋Š” ์ˆจ๊ธฐ๊ณ , ์ธ์‡„ ์‹œ์—๋Š” ํ‘œ์‹œํ•˜๋„๋ก ์„ค์ •

 

์˜ˆ์‹œ ์ฝ”๋“œ

import React, { useRef } from "react";
import { useReactToPrint } from "react-to-print";

function TransactionStatement() {
const printRef = useRef(null);

const handlePrint = useReactToPrint({
content: () => printRef.current, // ์ธ์‡„ํ•  ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ฐ˜ํ™˜
documentTitle: "๊ฑฐ๋ž˜๋ช…์„ธํ‘œ",
pageStyle: `
@page {
size: A4 landscape; /* A4 ๊ฐ€๋กœ๋กœ ์„ค์ • */
margin: 0;
}

  @media print {
    body {
      margin: 0;
      padding: 0;
    }
    /* ์ธ์‡„ ์‹œ์—๋งŒ ์ ์šฉํ•  ์Šคํƒ€์ผ ์˜ค๋ฒ„๋ผ์ด๋“œ */
    .print-area {
      width: 297mm;   /* A4 ๊ฐ€๋กœ ๊ธธ์ด */
      height: 210mm;  /* A4 ์„ธ๋กœ ๊ธธ์ด */
      display: flex;
      flex-direction: row;
    }
    .half-page {
      width: 50%;
      padding: 10mm;
      box-sizing: border-box;
    }
    .print-border {
      border-left: 1px solid #ccc;
    }

    /* ํ™”๋ฉด์—๋Š” ์ˆจ๊ฒจ๋†จ๋˜ ์˜์—ญ๋„ ์ธ์‡„ ์‹œ์—๋Š” ๋ณด์ด๋„๋ก */
    .print-only {
      display: block !important;
    }
  }
`,
});

return (


{/* ์ธ์‡„ ๋ฒ„ํŠผ */}
์ธ์‡„
  {/* ์ธ์‡„ ์˜์—ญ */}
  <div ref={printRef} className="print-area">
    {/* (1) ํ™”๋ฉด์—๋„ ๋ณด์ด๋Š” ์˜์—ญ (์ขŒ์ธก) */}
    <div className="half-page">
      <h2>๊ฑฐ๋ž˜๋ช…์„ธํ‘œ (ํ™”๋ฉด & ์ธ์‡„)</h2>
      <p>์ขŒ์ธก ์˜์—ญ ๋‚ด์šฉ...</p>
    </div>

    {/* (2) ํ™”๋ฉด์—๋Š” ๋ณด์ด์ง€ ์•Š๊ณ , ์ธ์‡„ ์‹œ์—๋งŒ ๋ณด์ด๋Š” ์˜์—ญ (์šฐ์ธก) */}
    <div className="hidden half-page print-border print-only">
      <h2>๊ฑฐ๋ž˜๋ช…์„ธํ‘œ (์ธ์‡„ ์ „์šฉ ์šฐ์ธก)</h2>
      <p>์šฐ์ธก ์˜์—ญ ๋‚ด์šฉ...</p>
    </div>
  </div>
</div>
);
}
export default TransactionStatement;

 

1. useReactToPrint
• content ์˜ต์…˜์— ์ธ์‡„ํ•  DOM(printRef.current)์„ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.
• pageStyle์— ์ธ์‡„ ์‹œ ์ ์šฉํ•  CSS๋ฅผ ๋ฌธ์ž์—ด๋กœ ๋„ฃ์–ด์ค๋‹ˆ๋‹ค.

2. @page { size: A4 landscape; }
• ๊ฐ€๋กœ ๋ฐฉํ–ฅ(A4 Landscape)์œผ๋กœ ์ธ์‡„๋˜๋„๋ก ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

3. .print-only ํด๋ž˜์Šค
• ํ™”๋ฉด์—์„œ display: none ์ฒ˜๋ฆฌํ•œ ๋’ค, @media print์—์„œ๋Š” display: block !important;๋กœ ๋‹ค์‹œ ํ‘œ์‹œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
• ์œ„ ์˜ˆ์‹œ์—์„œ๋Š” Tailwind CSS์˜ hidden ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜๊ณ , ์ถ”๊ฐ€๋กœ print-only ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด ์ธ์‡„ ์‹œ ๋ณด์ด๋„๋ก ๊ฐ•์ œํ–ˆ์Šต๋‹ˆ๋‹ค.

4. .half-page ๋ ˆ์ด์•„์›ƒ
• ์ขŒ์šฐ ๊ฐ๊ฐ 50% ๋„ˆ๋น„๋ฅผ ์ฐจ์ง€ํ•˜๋„๋ก ํ•˜์—ฌ A4 ๊ฐ€๋กœ ํ•œ ์žฅ์„ ๋ฐ˜์œผ๋กœ ๋‚˜๋ˆˆ ๋ ˆ์ด์•„์›ƒ์„ ๊ตฌ์„ฑํ•ฉ๋‹ˆ๋‹ค.
• ๊ฐ€์šด๋ฐ ๊ฒฝ๊ณ„์„ ์„ ์œ„ํ•ด .print-border ํด๋ž˜์Šค์— border-left: 1px solid #ccc; ์„ค์ •์„ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค.

 

์ธ์‡„ ์Šคํƒ€์ผ ์˜ค๋ฒ„๋ผ์ด๋“œ @media print

ํ”„๋กœ์ ํŠธ์—์„œ ํ™”๋ฉด์— ํ‘œ์‹œ๋˜๋Š” UI์™€ ์‹ค์ œ ์ธ์‡„ ์‹œ ํ‘œ์‹œ๋˜์–ด์•ผ ํ•  ๋ ˆ์ด์•„์›ƒ์ด ํฌ๊ฒŒ ๋‹ฌ๋ผ์•ผ ํ•  ๋•Œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.
์˜ˆ๋ฅผ ๋“ค์–ด ํ™”๋ฉด์—์„œ๋Š” ํฌ๊ฒŒ ๋ณด์ด๋˜ ํฐํŠธ๋ฅผ ์ธ์‡„ ์‹œ ์ž‘๊ฒŒ ์ถ•์†Œํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๊ทธ๋ ‡์ฃ .

์ด๋Ÿฐ ๋ฌธ์ œ๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด, @media print๋ฅผ ์‚ฌ์šฉํ•ด ์ธ์‡„ ์‹œ์—๋งŒ ์ ์šฉ๋˜๋Š” ๋ณ„๋„์˜ CSS ๊ทœ์น™์„ ์ •์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๋ ˆ์ด์•„์›ƒ, ํฐํŠธ ํฌ๊ธฐ, ์—ฌ๋ฐฑ, ํ…Œ์ด๋ธ” ๋„ˆ๋น„ ๋“ฑ์„ ํ™”๋ฉด๊ณผ ์ธ์‡„ ์šฉ๋„๋กœ ๋‚˜๋ˆ„์–ด ๊ด€๋ฆฌํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

@media print๋Š” CSS ํ‘œ์ค€์˜ ์ผ๋ถ€๋กœ, ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์ธ์‡„(ํ”„๋ฆฐํŠธ) ๋ชจ๋“œ๋กœ ์ „ํ™˜๋  ๋•Œ ์ž๋™์œผ๋กœ ์ ์šฉ๋˜๋Š” ๋ฏธ๋””์–ด ์ฟผ๋ฆฌ์ž…๋‹ˆ๋‹ค. ์ฆ‰, ํŠน๋ณ„ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋‚˜ ์„ค์ •์„ ์ถ”๊ฐ€๋กœ ํ•˜์ง€ ์•Š์•„๋„, ๋ธŒ๋ผ์šฐ์ €๋Š” ์ธ์‡„ ์‹œ์ ์— @media print ๊ตฌ๋ฌธ ๋‚ด๋ถ€์˜ ์Šคํƒ€์ผ์„ ์šฐ์„  ์ ์šฉํ•ฉ๋‹ˆ๋‹ค.

 

์˜ˆ๋ฅผ ๋“ค์–ด, ๋„ˆ๋ฌด ๋งŽ์€ ๋‚ด์šฉ์ด ํ•œ ํŽ˜์ด์ง€์— ๋“ค์–ด๊ฐˆ ๋•Œ ํฐํŠธ๊ฐ€ ์ปค์„œ ์ž˜๋ฆฌ๋Š” ๊ฒฝ์šฐ, ์•„๋ž˜์™€ ๊ฐ™์ด ํฐํŠธ๋ฅผ ์ค„์—ฌ์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@media print {
/* ํ…Œ์ด๋ธ” ํฐํŠธ ์‚ฌ์ด์ฆˆ ์ถ•์†Œ ์˜ˆ์‹œ */
.custom-table .ant-table-cell,
.custom-table .ant-table-summary > tr {
font-size: 7px !important;
}

/* ํŽ˜์ด์ง€ ์—ฌ๋ฐฑ 0์œผ๋กœ ์„ธํŒ… */
body {
margin: 0;
padding: 0;
}
}

์ด๋Ÿฌํ•œ ์ธ์‡„ ์ „์šฉ ์Šคํƒ€์ผ์€ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ํ™”๋ฉด๊ณผ ์ธ์‡„๋ฅผ ๊ตฌ๋ถ„ํ•˜์—ฌ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์–ด์•ผ, ์˜๋„ํ•œ ๋ ˆ์ด์•„์›ƒ๊ณผ ์ •ํ™•ํžˆ ์ผ์น˜ํ•˜๊ฒŒ ์ธ์‡„๋ฅผ ์ง„ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

์ •๋ฆฌ

1. useReactToPrint + useRef๋กœ ํŠน์ • DOM์„ ์ธ์‡„ ๋Œ€์ƒ์œผ๋กœ ์ง€์ •.
2. ์ธ์‡„ ์ „์šฉ ์Šคํƒ€์ผ์€ @media print ๋‚ด๋ถ€์—์„œ ์ •์˜.
3. ํ™”๋ฉด์šฉ/์ธ์‡„์šฉ์„ ๊ตฌ๋ถ„ํ•ด ํ•„์š”์— ๋”ฐ๋ผ display๋ฅผ ๋‹ฌ๋ฆฌ ์ ์šฉ.
4. A4 ์‚ฌ์ด์ฆˆ ๊ฐ€๋กœ ๋ฐฉํ–ฅ์€ @page { size: A4 landscape; }๋กœ ์„ค์ •.

 

 

๊ฐœ์„  ์‚ฌํ•ญ์ด ์žˆ๋‹ค๋ฉด ์–ธ์ œ๋“  ๋Œ“๊ธ€๋กœ ๋‚จ๊ฒจ์ฃผ์„ธ์š”! ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.
728x90