๐ŸŒ€ React Portal๋กœ ๋…๋ฆฝ์ ์ธ UI ๊ตฌํ˜„ํ•˜๊ธฐ

zizonyoungjunยท6์ผ ์ „
1

์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋งŒ๋“ค๋‹ค ๋ณด๋ฉด ๋ชจ๋‹ฌ, ํˆดํŒ, ๋“œ๋กญ๋‹ค์šด ๋“ฑ UI ์š”์†Œ๋“ค์ด ํ•ญ์ƒ ์ตœ์ƒ๋‹จ์— ๋–  ์žˆ์–ด์•ผ ํ•  ๋•Œ๊ฐ€ ๋งŽ์Šต๋‹ˆ๋‹ค. ๊ฐ„ํ˜น ๊ณต๋“ค์—ฌ ์Šคํƒ€์ผ๋งํ•œ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ง‰์ƒ ์‚ฌ์šฉํ•˜๋‹ˆ ์Šคํƒ€์ผ ๊ณ„์ธต ๋•Œ๋ฌธ์— ๋ชจ์–‘์ด ์˜๋„์™€ ๋‹ค๋ฅด๊ฒŒ ๋‚˜ํƒ€๋‚˜๋Š” ๊ฒƒ์„ ๋‹ค๋“ค ๊ฒฝํ—˜ ํ•ด๋ณด์…จ์„ํ…๋ฐ์š”. ์ด๋Ÿฌํ•œ ์š”์†Œ๋“ค์„ ์„ค๊ณ„ํ•  ๋•Œ ๋ถ€๋ชจ ์š”์†Œ์˜ ์Šคํƒ€์ผ์ด๋‚˜ ์œ„์น˜๋ฅผ ๊ณ ๋ คํ•˜๋Š” ๊ฒƒ์ด ๊ณจ์น˜ ์•„ํŒŒ์ง€๋Š” ์ˆœ๊ฐ„์ด ์ข…์ข… ์ƒ๊ธฐ์ฃ  ๐Ÿคฆ ์ด๋•Œ ์œ ์šฉํ•˜๊ฒŒ ์“ฐ์ผ ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์ด ๋ฐ”๋กœ React Portal์ž…๋‹ˆ๋‹ค. Portal์„ ์‚ฌ์šฉํ•˜๋ฉด ์ปดํฌ๋„ŒํŠธ๋ฅผ React ํŠธ๋ฆฌ์—์„œ ๋ฒ—์–ด๋‚˜ ํŠน์ • DOM ์œ„์น˜์— ๋ Œ๋”๋งํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฒˆ ํฌ์ŠคํŠธ์—์„œ๋Š” React Portal์ด๋ž€ ๋ฌด์—‡์ธ์ง€, ๊ทธ๋ฆฌ๊ณ  ์ด๋ฅผ ์–ด๋–ป๊ฒŒ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋Š”์ง€๋ฅผ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค ๐Ÿง‘โ€๐Ÿ’ป

React Portal์ด๋ž€?

React Portal์€ React ์ปดํฌ๋„ŒํŠธ ํŠธ๋ฆฌ์™€ ๋ณ„๋„์˜ DOM ์œ„์น˜์— ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ Œ๋”๋งํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ฃผ๋Š” ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ React์—์„œ๋Š” ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ์˜ DOM ํŠธ๋ฆฌ ์•ˆ์—์„œ ์ž์‹ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ Œ๋”๋งํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋ถ€๋ชจ์™€ ์ž์‹ ์ปดํฌ๋„ŒํŠธ๋Š” ํ™”๋ฉด ์ƒ์—์„œ ๊ณ„์ธต์ ์œผ๋กœ ์—ฐ๊ฒฐ๋œ ๊ตฌ์กฐ๋ฅผ ๊ฐ€์ง€๊ฒŒ ๋˜๋Š”๋ฐ์š”๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ ํ•˜์ง€๋งŒ Portal์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ์˜ ๋…ผ๋ฆฌ์  ์—ฐ๊ฒฐ์€ ์œ ์ง€ํ•˜๋ฉด์„œ๋„, ์‹ค์ œ DOM ํŠธ๋ฆฌ์—์„œ๋Š” ์™„์ „ํžˆ ๋ณ„๋„์˜ ์œ„์น˜์— ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ Œ๋”๋งํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๋ชจ๋‹ฌ, ๋“œ๋กญ๋‹ค์šด, ํˆดํŒ ๊ฐ™์€ UI ์š”์†Œ๊ฐ€ ํ™”๋ฉด์—์„œ ๋…๋ฆฝ๋œ ์œ„์น˜์— ๋‚˜ํƒ€๋‚  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Portal์„ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•

React์—์„œ Portal์„ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ReactDOM.createPortal ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฉ”์„œ๋“œ๋Š” ๋ Œ๋”๋งํ•  ์ปดํฌ๋„ŒํŠธ์™€ ๋ Œ๋”๋ง๋  DOM ๋…ธ๋“œ๋ฅผ props๋กœ ๋ฐ›์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ๋ชจ๋‹ฌ์„ portal-root๋ผ๋Š” DOM ๋…ธ๋“œ์— ๋ Œ๋”๋งํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

import ReactDOM from 'react-dom';

function Modal({ children }) {
  return ReactDOM.createPortal(
    <div className="modal">{children}</div>,
    document.getElementById('portal-root')
  );
}

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด Modal ์ปดํฌ๋„ŒํŠธ๋Š” React ํŠธ๋ฆฌ์—์„œ๋Š” ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ์— ์†ํ•ด ์žˆ์ง€๋งŒ, ์‹ค์ œ DOM ๊ตฌ์กฐ์—์„œ๋Š” portal-root์— ๋ Œ๋”๋ง๋ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๋ถ€๋ชจ์˜ ์Šคํƒ€์ผ์— ์˜ํ–ฅ์„ ๋ฐ›์ง€ ์•Š๊ณ  ๋ชจ๋‹ฌ์„ ๋…๋ฆฝ์ ์œผ๋กœ ํ™”๋ฉด์— ํ‘œ์‹œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Portal์˜ ๋™์ž‘ ์›๋ฆฌ

์•ž์„œ ์„ค๋ช…๋“œ๋ฆฐ ๋ฐ”์™€ ๊ฐ™์ด, Portal์€ ReactDOM.createPortal์„ ํ†ตํ•ด React ์ปดํฌ๋„ŒํŠธ ํŠธ๋ฆฌ์˜ ๋…ผ๋ฆฌ์  ๊ตฌ์กฐ์™€ ์‹ค์ œ DOM ์œ„์น˜๋ฅผ ๋ถ„๋ฆฌํ•˜์—ฌ, ์ง€์ •ํ•œ DOM ๋…ธ๋“œ์— ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ Œ๋”๋งํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ด๋กœ ์ธํ•ด ์ปดํฌ๋„ŒํŠธ๋Š” ๋ถ€๋ชจ-์ž์‹ ๊ณ„์ธต ๊ตฌ์กฐ๋ฅผ ์œ ์ง€ํ•˜๋ฉด์„œ๋„ ์‹ค์ œ DOM ํŠธ๋ฆฌ์—์„œ๋Š” ๋…๋ฆฝ๋œ ์œ„์น˜์— ๋ Œ๋”๋ง๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Portal๋กœ ๋ Œ๋”๋ง๋œ ์ปดํฌ๋„ŒํŠธ๋Š” ์—ฌ์ „ํžˆ ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ์˜ props์™€ context์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์–ด, React์˜ ๋…ผ๋ฆฌ์  ๊ณ„์ธต ๊ตฌ์กฐ ๋‚ด์—์„œ ์ •์ƒ์ ์œผ๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ, Portal๋กœ ๋ Œ๋”๋ง๋œ ์š”์†Œ๋Š” React ์ปดํฌ๋„ŒํŠธ ํŠธ๋ฆฌ๋ฅผ ๋”ฐ๋ผ ์ด๋ฒคํŠธ ๋ฒ„๋ธ”๋ง์ด ๋ฐœ์ƒํ•˜๋ฏ€๋กœ, portal-root์— ๋ Œ๋”๋ง๋œ ๋ชจ๋‹ฌ์˜ ํด๋ฆญ ์ด๋ฒคํŠธ๋Š” ๋ฌผ๋ฆฌ์ ์ธ DOM ๊ตฌ์กฐ์™€ ๊ด€๊ณ„์—†์ด ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ๋กœ ์ „ํŒŒ๋ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด Portal์€ ๋ฌผ๋ฆฌ์  DOM ํŠธ๋ฆฌ์—์„œ๋Š” ๋…๋ฆฝ์ ์ธ ์œ„์น˜์— ์กด์žฌํ•˜๋”๋ผ๋„, React์˜ ๋…ผ๋ฆฌ์  ํŠธ๋ฆฌ ์•ˆ์—์„œ ๋ถ€๋ชจ-์ž์‹ ๊ด€๊ณ„๋ฅผ ๊ทธ๋Œ€๋กœ ์œ ์ง€ํ•˜๊ณ  ์žˆ์Œ์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

React Portal์˜ ์žฅ์ 

์ด๋Ÿฌํ•œ Portal์˜ ๊ฐ€์žฅ ํฐ ์žฅ์ ์€ ๋ ˆ์ด์•„์›ƒ ๋…๋ฆฝ์„ฑ์ž…๋‹ˆ๋‹ค. ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ์˜ ์Šคํƒ€์ผ์ด๋‚˜ overflow ์„ค์ •์— ๊ตฌ์• ๋ฐ›์ง€ ์•Š๊ณ , ๋ชจ๋‹ฌ, ๋“œ๋กญ๋‹ค์šด, ํˆดํŒ ๊ฐ™์€ UI ์š”์†Œ๋ฅผ ํ™”๋ฉด ์ตœ์ƒ๋‹จ์— ๋…๋ฆฝ์ ์œผ๋กœ ํ‘œ์‹œํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ๋ถ€๋ชจ ์š”์†Œ์— overflow: hidden์ด ์„ค์ •๋œ ๊ฒฝ์šฐ ์ผ๋ฐ˜์ ์ธ DOM ํŠธ๋ฆฌ ๊ตฌ์กฐ์—์„œ๋Š” ์ž์‹ ์š”์†Œ๊ฐ€ ํ™”๋ฉด ๋ฐ–์œผ๋กœ ๋ณด์ด์ง€ ์•Š์ง€๋งŒ, Portal์„ ์‚ฌ์šฉํ•˜๋ฉด ์ด๋Ÿฌํ•œ ์ œ์•ฝ์„ ๋›ฐ์–ด๋„˜์–ด ํ•ญ์ƒ ์›ํ•˜๋Š” ์œ„์น˜์— UI ์š”์†Œ๋ฅผ ํ‘œ์‹œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋˜ํ•œ, Portal์€ ๋ณต์žกํ•œ UI์—์„œ๋„ ๊ตฌ์กฐ๋ฅผ ๊น”๋”ํ•˜๊ฒŒ ์œ ์ง€ํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค. ๋“œ๋กญ๋‹ค์šด ๋ฉ”๋‰ด๋‚˜ ๋ชจ๋‹ฌ์ฒ˜๋Ÿผ DOM ํŠธ๋ฆฌ ์ตœ์ƒ๋‹จ ๋ ˆ์ด์–ด์— ์œ„์น˜ํ•ด์•ผ ํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ถ€๋ชจ์˜ DOM ๊ตฌ์กฐ์™€ ๋ฌด๊ด€ํ•˜๊ฒŒ ์‰ฝ๊ฒŒ ๋ฐฐ์น˜ํ•  ์ˆ˜ ์žˆ์–ด, ๋ ˆ์ด์•„์›ƒ์˜ ์ผ๊ด€์„ฑ์„ ํ•ด์น˜์ง€ ์•Š์œผ๋ฉด์„œ๋„ ์ƒ์œ„ ๋ ˆ์ด์–ด์—์„œ ์ž์œ ๋กญ๊ฒŒ ๋™์ž‘ํ•˜๋„๋ก ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฒฐ๋ก 

React Portal์€ ๋ชจ๋‹ฌ, ๋“œ๋กญ๋‹ค์šด, ํˆดํŒ ๋“ฑ ํŠน์ • UI ์š”์†Œ๊ฐ€ ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ์˜ ์Šคํƒ€์ผ์ด๋‚˜ ๋ ˆ์ด์•„์›ƒ์— ์ œ์•ฝ๋ฐ›์ง€ ์•Š๊ณ  ํ™”๋ฉด์— ๋…๋ฆฝ์ ์œผ๋กœ ํ‘œ์‹œ๋  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ค๋‹ˆ๋‹ค. Portal์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ณต์žกํ•œ UI์—์„œ๋„ ๊ตฌ์กฐ์ ์ธ ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•˜๋ฉด์„œ, ์ƒ์œ„ ๋ ˆ์ด์–ด์— ์ž์œ ๋กญ๊ฒŒ ๋ฐฐ์น˜ํ•  ์ˆ˜ ์žˆ๋Š” ์œ ์—ฐ์„ฑ์„ ํ™•๋ณดํ•  ์ˆ˜ ์žˆ์ฃ . ๋˜ํ•œ, React์˜ ๋…ผ๋ฆฌ์  ๊ณ„์ธต ๊ตฌ์กฐ๋ฅผ ๊ทธ๋Œ€๋กœ ์œ ์ง€ํ•˜๋ฏ€๋กœ props์™€ context๋ฅผ ํ†ตํ•ด ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ์™€์˜ ์—ฐ๊ฒฐ์„ฑ์„ ์žƒ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ํŠน์ง•์„ ๋ฐ”ํƒ•์œผ๋กœ, Portal์€ ๋ณต์žกํ•œ UI๋ฅผ ๋ณด๋‹ค ์ง๊ด€์ ์ธ ๋ฐฉ์‹์œผ๋กœ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ฃผ๋Š” ์ค‘์š”ํ•œ ๋„๊ตฌ์ž…๋‹ˆ๋‹ค. Portal์œผ๋กœ ์—ฌ๋Ÿฌ๋ถ„์˜ ๋ชจ๋‹ฌ์— ์ž์œ ๋ฅผ ์„ ๋ฌผํ•ด๋ณด์„ธ์š” ! ๐Ÿง™โ€โ™‚๏ธ

post-custom-banner

0๊ฐœ์˜ ๋Œ“๊ธ€