๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
์นดํ…Œ๊ณ ๋ฆฌ ์—†์Œ

๐Ÿง  ๋ฌดํ•œ ์Šคํฌ๋กค, ๊ฐ€์ƒ ๋ฆฌ์ŠคํŠธ, ๊ทธ๋ฆฌ๊ณ  Lazy Rendering

by mingzoo 2025. 4. 8.

ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์„ ํ•˜๋‹ค ๋ณด๋ฉด ๋ฆฌ์ŠคํŠธ ๋ Œ๋”๋ง ๊ด€๋ จ ๊ณ ๋ฏผ์€ ๋Š˜ ๋น ์ง€์ง€ ์•Š์ฃ . ํŠนํžˆ "๋งŽ์€ ๋ฐ์ดํ„ฐ๋ฅผ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉ์ž์—๊ฒŒ ๋น ๋ฅด๊ฒŒ, ๋ถ€๋“œ๋Ÿฝ๊ฒŒ ๋ณด์—ฌ์ค„ ๊ฒƒ์ธ๊ฐ€?"๋Š” ๋ชจ๋“  ์„œ๋น„์Šค์—์„œ ์ค‘์š”ํ•œ ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค.

์ตœ๊ทผ ์ €๋Š” ๊ตฌ์„ฑ์› ์ •๋ณด๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ํ…Œ์ด๋ธ” UI๋ฅผ ๋ฆฌ๋‰ด์–ผํ•˜๋ฉด์„œ ์ด ๋ฌธ์ œ๋ฅผ ์ง์ ‘ ๊ฒช์—ˆ๊ณ , ๊ทธ ํ•ด๊ฒฐ์„ ์œ„ํ•ด IntersectionObserver ๊ธฐ๋ฐ˜ Lazy Rendering์„ ์„ ํƒํ–ˆ์Šต๋‹ˆ๋‹ค. ์˜ค๋Š˜์€ ๊ทธ ์—ฌ์ •๊ณผ ์‹ค๋ฌด ์ ์šฉ ํฌ์ธํŠธ๋ฅผ ๊ณต์œ ํ•ด๋ณด๋ ค ํ•ฉ๋‹ˆ๋‹ค.


๐Ÿงฉ ๊ธฐ์กด ๊ตฌ์กฐ์˜ ํ•œ๊ณ„: ํŽ˜์ด์ง€๋„ค์ด์…˜์—์„œ ๋ฌดํ•œ ์Šคํฌ๋กค๋กœ

๊ธฐ์กด ๊ตฌ์„ฑ์› ์ •๋ณด ํŽ˜์ด์ง€๋Š” ํŽ˜์ด์ง€๋„ค์ด์…˜ ๊ธฐ๋ฐ˜์ด์—ˆ์Šต๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž๋Š” 1ํŽ˜์ด์ง€, 2ํŽ˜์ด์ง€๋ฅผ ๋„˜๊ธฐ๋ฉฐ ๋ฐ์ดํ„ฐ๋ฅผ ๋ด์•ผ ํ–ˆ๊ณ , UX ์ธก๋ฉด์—์„œ ๊ฝค ๋ถˆํŽธํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด์— ๋”ฐ๋ผ:

  • โœ… ๋” ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋ฐ์ดํ„ฐ๋ฅผ ํƒ์ƒ‰ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฌดํ•œ ์Šคํฌ๋กค๋กœ ๋ณ€๊ฒฝ
  • โ— ํ•˜์ง€๋งŒ ๋ฌดํ•œ ์Šคํฌ๋กค๋กœ ์ „ํ™˜ํ•˜์ž ๊ณง๋ฐ”๋กœ ๋ Œ๋”๋ง ์„ฑ๋Šฅ ์ด์Šˆ๊ฐ€ ๋‚˜ํƒ€๋‚ฌ์Šต๋‹ˆ๋‹ค

๋ฌธ์ œ๋Š” "๋ Œ๋”๋ง์ด ๋„ˆ๋ฌด ๋งŽ๋‹ค"๋Š” ๊ฒƒ.
๋ฆฌ์ŠคํŠธ ๋ฐ์ดํ„ฐ๋ฅผ ๋ชจ๋‘ ๋ Œ๋”๋งํ•ด๋ฒ„๋ฆฌ๋ฉด ๋ธŒ๋ผ์šฐ์ € ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ํ„ฐ์งˆ ์ˆ˜๋„(?) ์žˆ์ฃ . ํŠนํžˆ ๊ฐ ๊ตฌ์„ฑ์›๋งˆ๋‹ค ํ”„๋กœํ•„ ์ด๋ฏธ์ง€(Avatar), ์•„์ด์ฝ˜, ์ƒ์„ธ์ •๋ณด ๋“ฑ์ด ๋ณต์žกํ•˜๊ฒŒ ์–ฝํ˜€ ์žˆ๋˜ ํ„ฐ๋ผ ์„ฑ๋Šฅ์ด ๊ธ‰๊ฒฉํžˆ ๋–จ์–ด์กŒ์Šต๋‹ˆ๋‹ค.


๐Ÿ” ๊ฐ€์ƒ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋„์ž…ํ• ๊นŒ? ๊ณ ๋ฏผ์˜ ์‹œ์ž‘

๊ฐ€์žฅ ๋จผ์ € ๋– ์˜ค๋ฅธ ๊ฑด ๋‹น์—ฐํžˆ ๊ฐ€์ƒ ๋ฆฌ์ŠคํŠธ(Virtual List) ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜€์Šต๋‹ˆ๋‹ค.

react-window, react-virtualized, @tanstack/virtual ๋“ฑ ํ›Œ๋ฅญํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ๋งŽ์ฃ .

ํ•˜์ง€๋งŒ ํ˜„์‹ค์€ ์–ธ์ œ๋‚˜ ์ด์ƒ๊ณผ ๋‹ค๋ฆ…๋‹ˆ๋‹ค...

๊ฐ€์ƒ ๋ฆฌ์ŠคํŠธ์˜ ๋„์ž…์ด ์–ด๋ ค์› ๋˜ ์ด์œ 

  • ์šฐ๋ฆฌ ๋ฆฌ์ŠคํŠธ๋Š” ๋‹จ์ˆœํ•œ ํ…์ŠคํŠธ๊ฐ€ ์•„๋‹ˆ๋ผ ์ค‘์ฒฉ๋œ ํ…Œ์ด๋ธ” ๊ตฌ์กฐ + ๋ ˆ์ด์•„์›ƒ์ด ๋‹ค์ด๋‚˜๋ฏน
  • ์Šคํฌ๋กค ์ปจํ…Œ์ด๋„ˆ๊ฐ€ iframe ๊ตฌ์กฐ๋ฅผ ํƒ€๊ณ  ๋“ค์–ด๊ฐ€ ์žˆ์–ด ์ง์ ‘ ์ œ์–ด๊ฐ€ ์–ด๋ ค์›€
  • ๊ธฐ์กด ์ฝ”๋“œ์™€ ๊ฐ€์ƒ ๋ฆฌ์ŠคํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ๊ถํ•ฉ์ด ์•ˆ ๋งž์•„, ๋„์ž… ๋‚œ์ด๋„๊ฐ€ ๋†’์Œ

→ "์ข‹์€ ๊ธฐ์ˆ ์ด์–ด๋„ ๋„์ž… ๋น„์šฉ์ด ๋„ˆ๋ฌด ํฌ๋‹ค๋ฉด, ์‹ค๋ฌด์—์„  ์ ์ ˆํ•˜์ง€ ์•Š๋‹ค"


๐ŸŽฏ ๊ทธ๋ž˜์„œ ์„ ํƒํ•œ ๊ฒƒ์€ IntersectionObserver ๊ธฐ๋ฐ˜ Lazy Rendering

๋ณต์žกํ•œ ๊ตฌ์กฐ๋ฅผ ๊ฑด๋“œ๋ฆฌ์ง€ ์•Š์œผ๋ฉด์„œ๋„, ํ˜„์žฌ ๋ณด์ด๋Š” ์š”์†Œ๋งŒ ๋ Œ๋”๋งํ•˜๊ณ  ์‹ถ์—ˆ๊ณ , ๊ทธ๋ž˜์„œ ๋– ์˜ค๋ฅธ ๊ฒŒ IntersectionObserver์˜€์Šต๋‹ˆ๋‹ค.

 
const observer = new IntersectionObserver((entries) => { entries.forEach((entry) => { if (entry.isIntersecting) { setIsRendered(true); } }); }, { root: document.getElementById("main-content-box"), threshold: 0.1, });

ํ•ต์‹ฌ์€ ์—ฌ๊ธฐ ๐Ÿ‘‡

  • root๋ฅผ null์ด ์•„๋‹Œ #main-content-box๋กœ ์ง€์ •
    → ์‹ค์ œ ์Šคํฌ๋กค์ด ๋ฐœ์ƒํ•˜๋Š” ์ง€์ •๋œ ์ปจํ…Œ์ด๋„ˆ ๊ธฐ์ค€์œผ๋กœ ์ •ํ™•ํ•œ ๊ฐ์ง€
  • threshold๋ฅผ ์กฐ์ •ํ•ด ์–ผ๋งˆ๋‚˜ ๋ณด์—ฌ์•ผ "๋ Œ๋”๋งํ•˜์ž"๊ณ  ํŒ๋‹จํ• ์ง€ ์ •ํ•จ
  • isRendered ํ”Œ๋ž˜๊ทธ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ Avatar, Icon ๋“ฑ์„ ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง

๋‹จ์ˆœํ•˜๋ฉด์„œ๋„ ์œ ์—ฐํ•˜๊ฒŒ, ์ง„์งœ ๋ณด์ด๋Š” ๊ฒƒ๋งŒ ๋ Œ๋”๋งํ•˜๋Š” ๊ตฌ์กฐ ์™„์„ฑ!


๐Ÿ’ก Lazy Rendering์˜ ์žฅ์  (vs Virtual List)

๋น„๊ต ํ•ญ๋ชฉLazy Rendering (IntersectionObserver)Virtual List
์ ์šฉ ๋‚œ์ด๋„ โœ… ๋‚ฎ์Œ (๊ธฐ์กด ์ฝ”๋“œ ๊ฑฐ์˜ ์œ ์ง€) โŒ ๋†’์Œ (๊ตฌ์กฐ ์žฌ์ •๋น„ ํ•„์š”)
์œ ์—ฐ์„ฑ โœ… ์ปดํฌ๋„ŒํŠธ๋งˆ๋‹ค ๊ฐœ๋ณ„ ์ œ์–ด ๊ฐ€๋Šฅ โŒ ๋‹จ์ผ ๋ฆฌ์ŠคํŠธ๋กœ๋งŒ ๊ตฌ์„ฑ
์„ฑ๋Šฅ ์ตœ์ ํ™” โœ… ์‹ค์งˆ์  ๋ Œ๋”๋ง ์ˆ˜ ๊ฐ์†Œ โœ… DOM ์ˆ˜ ์ œํ•œ์œผ๋กœ ์ตœ์ 
๋ถ€์ž‘์šฉ โŒ ์ƒํƒœ ์ดˆ๊ธฐํ™” ์ด์Šˆ ๊ฐ€๋Šฅ โŒ ์Šคํฌ๋กค/๋ ˆ์ด์•„์›ƒ ๊นจ์งˆ ์ˆ˜ ์žˆ์Œ

โœจ ๊ฒฐ๊ณผ์™€ ํšจ๊ณผ

  • ์ตœ์ดˆ ๋ Œ๋”๋ง DOM ์ˆ˜ ์•ฝ 80% ๊ฐ์†Œ
  • ๋ถˆํ•„์š”ํ•œ ์ปดํฌ๋„ŒํŠธ ๋ Œ๋”๋ง ์ œ๊ฑฐ
  • ์‚ฌ์šฉ์ž ์ฒด๊ฐ ์„ฑ๋Šฅ ํ–ฅ์ƒ (์Šคํฌ๋กค ๋ถ€๋“œ๋Ÿฌ์›€ + ๋กœ๋”ฉ ์ง€์—ฐ ์—†์Œ)
  • Virtual Scroll ๋„์ž… ์—†์ด๋„ ํผํฌ๋จผ์Šค ์ตœ์ ํ™” ๋‹ฌ์„ฑ

๐Ÿงญ ๊ฒฐ๋ก : ์ •๋‹ต์€ ์—†๋‹ค. “์ง€๊ธˆ” ์šฐ๋ฆฌ์—๊ฒŒ ๋งž๋Š” ํ•ด๋ฒ•์ด ์ค‘์š”

"๊ธฐ์ˆ  ์ž์ฒด๋ณด๋‹ค ์ค‘์š”ํ•œ ๊ฑด ์ƒํ™ฉ์— ๋งž๋Š” ํŒ๋‹จ๊ณผ ์‹คํ–‰์ด๋‹ค"

๊ฐ€์ƒ ๋ฆฌ์ŠคํŠธ๋Š” ํ›Œ๋ฅญํ•œ ๊ธฐ์ˆ ์ด์ง€๋งŒ, ํ˜„์žฌ์˜ ๊ตฌ์กฐ์™€ ์—ฌ๊ฑด์—์„œ๋Š” ์˜คํžˆ๋ ค ๋” ํฐ ๋ถ€๋‹ด์ด ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜คํžˆ๋ ค IntersectionObserver๋Š” ์ž‘์ง€๋งŒ ์ •ํ™•ํ•œ ์„ ํƒ์ด์—ˆ์Šต๋‹ˆ๋‹ค.

์ง€๊ธˆ ์—ฌ๋Ÿฌ๋ถ„์˜ ํ”„๋กœ์ ํŠธ์—์„œ๋„ "๋ Œ๋”๋ง์ด ๋„ˆ๋ฌด ๋งŽ์•„์„œ ๋А๋ฆฌ๋‹ค"๋Š” ์ด์Šˆ๊ฐ€ ์žˆ๋‹ค๋ฉด,
๊ผญ ๊ฑฐ์ฐฝํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋„์ž…์ด ์•„๋‹ˆ์–ด๋„ IntersectionObserver ๊ธฐ๋ฐ˜ Lazy Rendering์„ ๊ณ ๋ คํ•ด๋ณด์„ธ์š”.

๊ฐ„๊ฒฐํ•œ ์ฝ”๋“œ, ์ฆ‰๊ฐ์ ์ธ ์„ฑ๋Šฅ ๊ฐœ์„ , ๊ทธ๋ฆฌ๊ณ  ๊ฐœ๋ฐœ์ž์˜ ํ–‰๋ณต๊นŒ์ง€ ๋ค์œผ๋กœ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๐Ÿ˜Ž

728x90