๐Ÿงฉ ๊ฐ€์ƒ ์Šคํฌ๋กค( Virtualized List ) ํ™˜๊ฒฝ์—์„œ ๊ด‘๊ณ  ๋ฐฐ์น˜ ์ด์Šˆ & ํ•ด๊ฒฐ ์ „๋žต ๊ธฐ๋ก

์ฝ”์ธ ๋งˆ์ผ“, ๊ฑฐ๋ž˜์†Œ, ๊ฐ€๊ฒฉ ๋ฆฌ์ŠคํŠธ์ฒ˜๋Ÿผ ๋Œ€๋Ÿ‰ ๋ฐ์ดํ„ฐ UI๋ฅผ ๋‹ค๋ฃจ๋Š” ์„œ๋น„์Šค์—์„œ๋Š” ์„ฑ๋Šฅ ์ตœ์ ํ™”๋ฅผ ์œ„ํ•ด ๋Œ€๋ถ€๋ถ„ ๊ฐ€์ƒ ์Šคํฌ๋กค(virtualized list) ๊ตฌ์กฐ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
ํ•˜์ง€๋งŒโ€ฆ๊ด‘๊ณ (AdSense ๋“ฑ)๋ฅผ ๋ฆฌ์ŠคํŠธ ๋‚ด๋ถ€ ์š”์†Œ๋กœ ์‚ฝ์ž…ํ•˜๋Š” ์ˆœ๊ฐ„ ๋ฌธ์ œ๊ฐ€ ์‹œ์ž‘๋œ๋‹ค.

๐Ÿšจ ๋ฌธ์ œ ์ƒํ™ฉ

๊ฐ€์ƒ ์Šคํฌ๋กค ๊ตฌ์กฐ์—์„œ ๊ด‘๊ณ  ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ฆฌ์ŠคํŠธ ์•„์ดํ…œ์ฒ˜๋Ÿผ ์ทจ๊ธ‰ํ•˜๋ฉด ๋‹ค์Œ ํ˜„์ƒ์ด ๋ฐœ์ƒํ•œ๋‹ค.
  • viewport ๋ฐ– ์š”์†Œ โ†’ unmount
  • ๋‹ค์‹œ ๋“ค์–ด์˜ค๋ฉด โ†’ remount
  • remount ์‹œ โ†’ ๊ด‘๊ณ  ์žฌ์š”์ฒญ ๋ฐœ์ƒ
notion image

๐Ÿ’ฅ ์‹ค์ œ๋กœ ๋ฐœ์ƒํ•˜๋Š” ๋ฆฌ์Šคํฌ

์ด ๊ตฌ์กฐ๊ฐ€ ๊ด‘๊ณ  ์‹œ์Šคํ…œ๊ณผ ์ถฉ๋Œํ•˜๋ฉด์„œ ์ƒ๊ธฐ๋Š” ์˜ํ–ฅ:
  • CTR ํ•˜๋ฝ
  • RPM ํ•˜๋ฝ
  • Google Ads ํ’ˆ์งˆ ์‹ ํ˜ธ ์•…ํ™” ๊ฐ€๋Šฅ์„ฑ
  • ๋น„์ •์ƒ ์š”์ฒญ ํŒจํ„ด ๊ฐ์ง€ ๊ฐ€๋Šฅ์„ฑ
  • ์ตœ์•…์˜ ๊ฒฝ์šฐ โ†’ ๊ณ„์ • ๋ฆฌ์Šคํฌ

๐Ÿง  ์™œ ์ด๋Ÿฐ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ• ๊นŒ?

์ด์œ ๋Š” ๊ฐ€์ƒ ์Šคํฌ๋กค์˜ ๊ธฐ๋ณธ ๋™์ž‘ ๋ฐฉ์‹ ๋•Œ๋ฌธ์ด๋‹ค.
notion image
๊ฐ€์ƒ ์Šคํฌ๋กค์€ viewport ๋‚ด ๋ณด์ด๋Š” ์š”์†Œ๋“ค์— ๋Œ€ํ•ด์„œ๋งŒ DOM์„ ์œ ์ง€ํ•˜๊ณ  ๋‚˜๋จธ์ง€๋Š” ์ œ๊ฑฐํ•จ์œผ๋กœ ์„ฑ๋Šฅ ์ตœ์ ํ™”๋ฅผ ํ•œ๋‹ค.
๋ฐ˜๋ฉด ๊ด‘๊ณ ์˜ ๊ฒฝ์šฐ ํ•œ ๋ฒˆ ๊ด‘๊ณ ๋ฅผ ๋กœ๋“œ๊ฐ€ ๋˜๋ฉด ์žฌ์š”์ฒญ ํ˜น์€ DOM์„ ์žฌ์ƒ์„ฑํ•˜์ง€ ์•Š๋Š” ์ด์ƒ ๊ด‘๊ณ ๊ฐ€ ์œ ์ง€๋œ๋‹ค.
์ด๋Š” ๊ฐ€์ƒ์Šคํฌ๋กค์˜ ๊ธฐ๋ณธ๋™์ž‘๊ณผ ๊ตฌ์กฐ์ ์ธ ์ถฉ๋Œ์„ ๋ฐœ์ƒํ•˜๊ฒŒ ๋˜์–ด remount ๋  ๋•Œ๋งˆ๊ฐ€ ๊ด‘๊ณ  ์žฌ์š”์ฒญํ•˜๋Š” ์ด์Šˆ๊ฐ€ ๋ฐœ์ƒํ•˜๊ฒŒ ๋œ๋‹ค.

๐ŸŽฏ ๋ชฉํ‘œ ์ •์˜

๊ถ๊ทน์ ์œผ๋กœ ์›ํ•˜๋Š” ์ƒํƒœ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค:
  • ๊ด‘๊ณ  DOM์€ ํ•ญ์ƒ ๋งˆ์šดํŠธ ์ƒํƒœ ์œ ์ง€
  • ๊ฐ€์ƒ ์Šคํฌ๋กค ์ƒ๋ช…์ฃผ๊ธฐ์˜ ์˜ํ–ฅ์„ ๋ฐ›์ง€ ์•Š๋„๋ก ๋ถ„๋ฆฌ
  • ๊ด‘๊ณ  ์žฌ์š”์ฒญ ์™„์ „ ์ฐจ๋‹จ

๐Ÿ›  ์‹œ๋„ํ–ˆ๋˜ ํ•ด๊ฒฐ ๋ฐฉ์•ˆ

1๏ธโƒฃ Overscan ํ™•์žฅ
์•„์ด๋””์–ด:
  • viewport ๋ฐ– ์˜์—ญ๊นŒ์ง€ DOM ์œ ์ง€
๊ฒฐ๊ณผ: โŒ ์‹คํŒจ
์ด์œ :
  • ์œ ์ € ์Šคํฌ๋กค ๋ฒ”์œ„ ์˜ˆ์ธก ๋ถˆ๊ฐ€
  • ๋น ๋ฅธ ์Šคํฌ๋กค ์‹œ ์—ฌ์ „ํžˆ unmount ๋ฐœ์ƒ
  • ๊ทผ๋ณธ ํ•ด๊ฒฐ ๋ถˆ๊ฐ€

2๏ธโƒฃ DOM KeepAlive

์•„์ด๋””์–ด:
  • ๊ด‘๊ณ  ์ปดํฌ๋„ŒํŠธ ๊ฐ•์ œ ์œ ์ง€
๊ฒฐ๊ณผ: โŒ ์‹คํŒจ
๋ฌธ์ œ์ :
  • ๋‚ด๋ถ€์ ์œผ๋กœ ๊ด‘๊ณ  ์žฌ์š”์ฒญ ๋ฐœ์ƒ
  • React ๋ ˆ๋ฒจ ์œ ์ง€ โ‰  ๊ด‘๊ณ  ์‹œ์Šคํ…œ ์œ ์ง€
  • DOM ์ด๋™ / ์ œ๊ฑฐ ์ž์ฒด๊ฐ€ ๋ฌธ์ œ

โœ… ์ตœ์ข… ํ•ด๊ฒฐ ์ „๋žต

์™ธ๋ถ€ ๋ Œ๋”๋ง + ์ขŒํ‘œ ๋™๊ธฐํ™” ( Sticky Portal ์ „๋žต )
๊ด‘๊ณ ๋ฅผ ๊ฐ€์ƒ์Šคํฌ๋กค ๋ฆฌ์ŠคํŠธ ์•„์ดํ…œ์œผ๋กœ ์ทจ๊ธ‰ํ•˜์ง€ ์•Š๋Š”๋‹ค.
  1. Spacer ๋ฐฐ์น˜ (๋ฆฌ์ŠคํŠธ ๋‚ด๋ถ€)
  • ๋ฆฌ์ŠคํŠธ ๋‚ด๋ถ€ ๊ด‘๊ณ ๊ฐ€ ๋ฐฐ์น˜๋˜์–ด์•ผ ํ•  ๊ณต๊ฐ„์— ๋™์ผ ํฌ๊ธฐ์˜ ๋นˆ div๋ฅผ ์‚ฝ์ž…ํ•œ๋‹ค
  • ์‚ฝ์ž…๋œ div๋Š” ๋‹ค์Œ ์—ญํ• ์„ ์ˆ˜ํ–‰ํ•˜๊ฒŒ ๋œ๋‹ค
    • ๋ ˆ์ด์•„์›ƒ ๊ณต๊ฐ„ ํ™•๋ณด
    • ๊ฐ€์ƒ ์Šคํฌ๋กค ๊ณ„์‚ฐ ์œ ์ง€
    • ๊ด‘๊ณ  DOM๊ณผ ๋ถ„๋ฆฌ
  1. ๊ด‘๊ณ  ๋…๋ฆฝ ๋ Œ๋”๋ง (๋ฆฌ์ŠคํŠธ ์™ธ๋ถ€)
  • ๊ด‘๊ณ  ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ฆฌ์ŠคํŠธ ์™ธ๋ถ€์— ๋ฐฐ์น˜ํ•˜๊ณ  position ๊ฐ’์œผ๋กœ absolute ๋ฅผ ์„ค์ •ํ•œ๋‹ค.
  • ์™ธ๋ถ€์— ๋ฐฐ์น˜๊ฐ€ ๋จ์œผ๋กœ ๋ฆฌ์ŠคํŠธ์˜ ๋žœ๋”๋ง ๋ผ์ดํ”„์‚ฌ์ดํด ์˜ํ–ฅ์„ ๋ฐ›์ง€ ์•Š๋Š” ์ƒํƒœ๊ฐ€ ๋˜๋ฉฐ, ์ด๋Š” DOM์ด ์œ ์ง€๋˜์–ด ๊ด‘๊ณ ์žฌ์š”์ฒญ ๋ฐœ์ƒ์„ ๋ฐฉ์ง€ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.
  1. ์ขŒํ‘œ ๊ณ„์‚ฐ & ๋™๊ธฐํ™”
  • ์™ธ๋ถ€์— ๋ฐฐ์น˜ํ•œ ๊ด‘๊ณ ๋ฅผ ์Šคํฌ๋กค์‹œ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์ด๋™๋˜๋„๋ก ํ•˜๊ธฐ ์œ„ํ•œ spacer ์œ„์น˜์™€ ๋™๊ธฐํ™” ์ž‘์—…์„ ์ง„ํ–‰ํ•œ๋‹ค.
    • positionIndex * virtualRowHeight:
    • ๊ฐ€์ƒ ์Šคํฌ๋กค์€ ๋ชจ๋“  row๊ฐ€ ๋™์ผ ๋†’์ด(virtualRowHeight)๋ผ๊ณ  ๊ฐ€์ •ํ•˜๊ณ  ์ขŒํ‘œ๋ฅผ ๊ณ„์‚ฐํ•œ๋‹ค:
      • ์•„์ดํ…œ ์œ„์น˜ = index * rowHeight
    • ์ด index๋Š” ์‹ค์ œ DOM index๊ฐ€ ์•„๋‹ˆ๋ผ, ๊ฐ€์ƒ ๋ฆฌ์ŠคํŠธ ๊ธฐ์ค€ ๋…ผ๋ฆฌ์  ์ˆœ์„œ(positionIndex) ์ด๋‹ค.
    • ๋ช‡ ๋ฒˆ์งธ ์œ„์น˜์— ๊ด‘๊ณ  spacer๊ฐ€ ์กด์žฌํ•˜๋Š”๊ฐ€? ๋ฆฌ์ŠคํŠธ๋‚ด ์–ด๋–ค ์ˆœ์„œ์— ์‚ฝ์ž…๋˜๋Š”๊ฐ€? ๋ฅผ ์˜๋ฏธํ•œ๋‹ค.
    • heightCorrection:
    • ๋†’์ด ์ฐจ์ด๋กœ ์ธํ•ด ๋ฐœ์ƒํ•˜๋Š” ๋ˆ„์  ๋ณด์ •๊ฐ’
    • ๊ธฐ๋ณธ์  ๊ฐ row ์š”์†Œ๋“ค์˜ ์œ„์น˜๋Š” positionIndex * virtualRowHeight ๋กœ ๊ณ„์‚ฐํ•˜๋ฉด ์ถฉ๋ถ„ํ•˜๋‹ค.
    • ํ•˜์ง€๋งŒ ๊ด‘๊ณ  ๊ฐ™์€ ์™ธ๋ถ€ ์‚ฝ์ž… ์š”์†Œ๋Š” ์ผ๋ฐ˜ row์™€ ๋‹ฌ๋ฆฌ ๋†’์ด๊ฐ€ ๋” ํด ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ถ”๊ฐ€ ๋ณด์ •์ด ํ•„์š”ํ•˜๋‹ค.
    • ์˜ˆ๋ฅผ ๋“ค์–ด:
    • ์ผ๋ฐ˜ row ๋†’์ด = 72px (virtualRowHeight),
    • ๊ด‘๊ณ  ๋†’์ด = 250px,
    • ๋ฆฌ์ŠคํŠธ ๋‚ด๋ถ€ spacer(๊ด‘๊ณ ์ž๋ฆฌ) = 250px
    • ๊ฐ€์ƒ ์Šคํฌ๋กค์€ row๋ฅผ 72px๋กœ ๊ณ„์‚ฐํ•˜๋ฉฐ ์Œ“์•„ ์˜ฌ๋ฆฌ๋Š”๋ฐ, ์‹ค์ œ ๋ ˆ์ด์•„์›ƒ์€ ๊ด‘๊ณ ๊ฐ€ ๋“ค์–ด๊ฐ„ ์ง€์ ๋ถ€ํ„ฐ ์ถ”๊ฐ€ ๋†’์ด(250-72) ๋งŒํผ ๋” ๋ฐ€๋ฆฌ๊ฒŒ ๋œ๋‹ค.
    • ๊ด‘๊ณ  spacer๊ฐ€ ์‹ค์ œ ๋†’์ด๋ฅผ ์ •ํ™•ํžˆ ์ฐจ์ง€ํ•˜๊ณ  ์žˆ์Œ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ , react-window์˜ ์œ„์น˜ ๊ณ„์‚ฐ ๋ชจ๋ธ์—์„œ๋Š” ์—ฌ์ „ํžˆ virtualRowHeight ๊ธฐ์ค€์œผ๋กœ๋งŒ offset์ด ๊ณ„์‚ฐ๋œ๋‹ค
      ๊ทธ ๊ฒฐ๊ณผ ๊ด‘๊ณ ๊ฐ€ ์‚ฝ์ž…๋œ ์ดํ›„๋ถ€ํ„ฐ ๊ฐ€์ƒ ๊ณ„์‚ฐ ์œ„์น˜์™€ ์‹ค์ œ ๋ ˆ์ด์•„์›ƒ ์‚ฌ์ด์— (adHeight - virtualRowHeight)
      ์ด ์˜ค์ฐจ๋ฅผ ๋ณด์ •ํ•˜๊ธฐ ์œ„ํ•œ ๊ฐ’์ด ๋ฐ”๋กœ heightCorrection ๋‹ค.

โœ… ์ตœ์ข… ๊ฒฐ๊ณผ

  • ๊ด‘๊ณ  unmount ๋ฐœ์ƒ ์—†์Œ
  • ๊ด‘๊ณ  ์žฌ์š”์ฒญ ์ œ๊ฑฐ
  • ์ตœ์ดˆ ๋กœ๋“œ ๊ด‘๊ณ  ์œ ์ง€
  • CTR, RPM ์˜ํ–ฅ ์—†์Œ
notion image
ย 

ยฉ 2026 dan.dev.log, All right reserved.

Built with NextJS

๐Ÿงฉ ๊ฐ€์ƒ ์Šคํฌ๋กค( Virtualized List ) ํ™˜๊ฒฝ์—์„œ ๊ด‘๊ณ  ๋ฐฐ์น˜ ์ด์Šˆ & ํ•ด๊ฒฐ ์ „๋žต ๊ธฐ๋ก | Dan DevLog