[๋ฆฌ์•กํŠธ] ๐Ÿคทโ€โ™€๏ธPortalโ“โžก๋ชจ๋‹ฌ ์ฐฝ ๋งŒ๋“ค์–ด๋ณด์ž

ํ”„๋ฆฐ์ดยท2024๋…„ 11์›” 28์ผ

Portalโžก๋ชจ๋‹ฌ์—์„œ ์ฃผ๋กœ ์‚ฌ์šฉ๐Ÿ™†โ€โ™€๏ธ

๐Ÿ‘ฉโ€๐Ÿฆฑ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ์˜ DOM ๊ณ„์ธต ๊ตฌ์กฐ ๋ฐ”๊นฅ์— ์žˆ๋Š”
DOM ๋…ธ๋“œ๋กœ ๐Ÿ‘ฉโ€์ž์‹์„ ๋ Œ๋”๋งํ•˜๋Š” ์ตœ๊ณ ์˜ ๋ฐฉ๋ฒ•์„ ์ œ๊ณต๐Ÿคฉ

ReactDom.createPortal(child, container)

์ฒซ ๋ฒˆ์งธ ์ธ์ž(child)โžก์—˜๋ฆฌ๋จผํŠธ, ๋ฌธ์ž์—ด ํ˜น์€ fragment์™€
๊ฐ™์€ ์–ด๋–ค ์ข…๋ฅ˜์ด๋“  ๋ Œ๋”๋ง ํ•  ์ˆ˜ ์žˆ๋Š” React ์ž์‹๐Ÿ‘ฉโ€

๐Ÿฑโ€๐Ÿ’ปProtals ์—†์ด ๋ชจ๋‹ฌ ๋งŒ๋“ค์–ด๋ณด๊ธฐ

App.js

์‹คํ–‰ํ•˜๋ฉด ๋ชจ๋‹ฌ ์—ด๊ธฐ ๋ฒ„ํŠผ ํ•˜๋‚˜๋ž‘ div ํ•˜๋‚˜๊ฐ€ ์ƒ๊น€

๐ŸŽจstyle ๊พธ๋ฉฐ์ฃผ๊ธฐ

โ–ถ๋ชจ๋‹ฌ ์—ด๊ธฐ ๋ฒ„ํŠผ div - modalWrapperStyle

โ–ถZ-Index 2 div - higherIndexWrapperStyle

<div style={higherIndexWrapperStyle}>
  Z-Index 2
</div>

๐Ÿค”์™œ relative๋กœ ์คฌ์„๊นŒโ“

relative ์•„๋‹ˆ์–ด๋„ ์ƒ๊ด€์—†์ง€๋งŒ ํฌ์ง€์…˜์„
๊ธฐ๋ณธ ๊ฐ’(static)์ด ์•„๋‹Œ ๋‹ค๋ฅธ ๊ฐ’์„ ์คฌ๋‹ค๋Š” ๊ฑด
zIndex ์‚ฌ์šฉํ•  ๋•Œ zIndex๋Š” ํฌ์ง€์…˜ static
์ด์™ธ์˜ ๊ฒƒ์ด ์žˆ์–ด์•ผ๋งŒ zIndex๊ฐ€ ๋จนํž˜ ๐ŸŒŸ


components>TestModal.js

App.js๋กœ TestModal ์ปดํฌ๋„ŒํŠธ ๊ฐ€์ ธ์˜ค๊ธฐ

๐ŸŽจstyle

modalStyle

overlayStyle

๐Ÿ’กbackgroundColor: 'rgba(0, 0, 0, 0.7)'

๐Ÿ’โ€โ™€๏ธ๋ชจ๋‹ฌ ๋‹ซ๊ธฐ ์ค‘์•™ ์ •๋ ฌํ•˜๋ ค๋ฉดโ“

X์—์„œ -50 ( width์— 50๋งŒํผ ์™ผ์ชฝ์œผ๋กœ ),
์œ„๋กœ 50% ๋งŒํผ ๋‚ด๋ ค์˜จ ๊ฑฐ๋‹ˆ๊นŒ -50๋งŒํผ ํ•ด์ฃผ๊ธฐ

ํ™”๋ฉด ์งค๋ ค์„œ ๊ทธ๋Ÿฌ๋Š”๋ฐ ๋”ฑ ์™„์ „ ์ •์ค‘์•™์— ๋ฐฐ์น˜ ๋œ ๊ฒƒโ—


๐Ÿ˜Ž๋ชจ๋‹ฌ ๊ธฐ๋Šฅ๋งŒ๋“ค๊ธฐ

App.js

๐ŸŽ‡state ์ƒ์„ฑํ•˜๊ธฐ

const [isModalOpen, setIsModalOpen] = useState(false);

.

{/* ๋ชจ๋‹ฌ */}
<TestModal
  open={isModalOpen}
  onclose={() => setIsModalOpen(false)}
>
  ๋ชจ๋‹ฌ ๋‚ด์šฉ
</TestModal>

.

<div style={modalWrapperStyle}>
  <button
    onClick={() => setIsModalOpen(true)}
  >
    ๋ชจ๋‹ฌ ์—ด๊ธฐ
  </button>

โฌ‡

๐Ÿฑโ€๐Ÿcomponents>TestModal.js

๐Ÿค”์ปดํฌ๋„ŒํŠธ ์•ˆ์— ๋„ฃ์–ด์ค€ ๋ถ€๋ถ„์€ ์–ด๋–ป๊ฒŒ ๊ฐ€์ ธ์˜ฌ๊นŒโ“

App.jsโžกTestModal.js๋กœ ๊ฐ€์ ธ์˜ค๊ธฐ

๐Ÿ‘ฉโ€Children์ด๋ผ๊ณ  ๊ฐ€์ ธ์˜ค๋ฉด ๋จโ—

Children์€ ์ •ํ•ด์ง„ ์ด๋ฆ„์ž„๐Ÿ™†โ€โ™€๏ธ

if (!open) return null;
๐Ÿ‘‰ ๋ชจ๋‹ฌ์ด ์•ˆ ์—ด๋ ค ์žˆ์œผ๋ฉด ์ฐฝ ์•ˆ ๋ณด์ด๊ฒŒ ํ•  ๊ฒƒ

๋ชจ๋‹ฌ์ฐฝ ์‚ฌ๋ผ์ง๐Ÿš€

๋ชจ๋‹ฌ ์—ด๊ธฐ ๋ฒ„ํŠผ ๋ˆ„๋ฅด๋ฉด ๋ชจ๋‹ฌ์ฐฝ์ด ์˜คํ”ˆ๋˜๊ณ 
๋ชจ๋‹ฌ ๋‹ซ๊ธฐ ๋ฒ„ํŠผ ๋ˆ„๋ฅด๋ฉด ๋ชจ๋‹ฌ์ฐฝ์ด ๋‹ซ์•„์ง


๐ŸงZ-Index 2๋ฅผ ๋ชจ๋‹ฌ๋ณด๋‹ค ์•ˆ์œผ๋กœ ๋“ค์–ด๊ฐ€๊ฒŒ ํ•˜๊ณ  ์‹ถ์€๋ฐ
์™œ Z-Index 2๊ฐ€ ๋” ์•ž์œผ๋กœ ๋‚˜์˜ค๋Š” ๊ฑธ๊นŒโ“

๊ฐ™์€ ๊ณ„์ธต์— ์žˆ์Œ

modalWrapperStyle(๋ชจ๋‹ฌ ์—ด๊ธฐ ๋ฒ„ํŠผ div)โžกzIndex 1๋กœ ์คฌ๊ณ 
higherIndexWrapperStyle(Z-Index 2)โžกzIndex 2๋กœ ์คฌ์Œ

์ž๋…€๋“ค์—์„œ zIndex๋ฅผ ์•„๋ฌด๋ฆฌ ํฌ๊ฒŒ ์ค˜๋„
์ด๋ฏธ ๋ถ€๋ชจ์—์„œ zIndex๊ฐ€ ์ง€์ •๋˜์–ด์„œ ์œ„๋กœ ์น˜๊ณ  ๋‚˜์˜จ ๊ฒƒ๐Ÿ”ฅ

์›์น˜ ์•Š๋Š” ๋ถ€๋ถ„์ด ๋ชจ๋‹ฌ ์œ„๋กœ ๋‚˜์™€ ๋ฒ„๋ฆฌ๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์ด ์žˆ์Œ๐Ÿ˜ค


๐Ÿง™โ€ํ•ด๊ฒฐ์‚ฌ Portal ์ด์šฉํ•˜์ž๐Ÿ”ฎ

๐ŸŽฅ๋‹ฅํ„ฐ ์ŠคํŠธ๋ ˆ์ธ์ง€๐ŸŽฌ
์ „ํˆฌ ์ค‘ ๋ถ„๋ฆฌํ•˜๋ฉด ํฌํƒˆ ๋งŒ๋“ค์–ด ์ƒํ™ฉ์„ ๋น ์ ธ๋‚˜๊ฐ
์•…๋‹น์„ ํฌํ„ธ๋กœ ๋„ฃ์–ด ์ˆœ์‹๊ฐ„์— ์ƒํ™ฉ ์ข…๋ฃŒ ์‹œ์ผœ ๋ฒ„๋ฆผ
๊น”๊น”๐Ÿ˜†

๋ฆฌ์•กํŠธ๋„ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์ด๋™์‹œํ‚ค๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตโ—
ํ‘œํ˜„์ด ์กฐ๊ธˆ ์ƒ์†Œํ•˜๊ธด ํ•˜์ง€๋งŒ
์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ๋งˆ์šดํŠธ ๋˜๋Š” ์œ„์น˜๋ฅผ ์ด๋™ํ•œ๋‹ค๋Š” ์˜๋ฏธ๐Ÿฑโ€๐Ÿ
๋ฃจํŠธ ๋” ํŠธ๋ฆฌ๋ฅผ ๋ฒ—์–ด๋‚˜ ๋”์—์„œ
์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ผ๋ถ€๋ถ„์„ ๊ทธ๋ฆด ์ˆ˜ ์žˆ์Œ๐Ÿ™„โ“

โœ…์ปจํ…Œ์ด๋„ˆ๊ฐ€ ๋ฆฌ์•กํŠธ์—์„  ํ•˜๋‚˜
๐Ÿ‘‰ Portal ๋งŒ๋“ค๋ฉด ์ปจํ…Œ์ด๋„ˆ ํ•˜๋‚˜ ๋” ์ƒ์„ฑ ํ•  ์ˆ˜ ์žˆ์Œ๐Ÿ‘€

index.html

root๋Š” ์ด๊ณณ์— ์žˆ์Œ

๐ŸŽ‡์ด๊ณณ์— protal ์ƒ์„ฑํ•˜๊ธฐ

์–ต์ง€๋กœ ์ƒ์„ฑํ•ด ๋†“์•˜์Œ

๋ชจ๋‹ฌ์„ root ์•ˆ์—์„œ ๋ Œ๋”๋ง ํ•˜๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ
portal ์•ˆ์— ๋ชจ๋‹ฌ์„ ๋„ฃ์„ ๊ฒƒ๐Ÿ™†โ€โ™€๏ธโœ”

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๋ชจ๋‹ฌ์ด ๋‹ค๋ฅธ ๊ณ„์ธต๋“ค ๋ณด๋‹ค ๋†’๊ฒ ์ ธโ“
๐Ÿ‘‰ zIndex์˜ ๋ฌธ์ œ์  ํ•ด๊ฒฐ ๋จ๐Ÿฅณ

๐Ÿคทโ€โ™€๏ธ์ €๋ถ€๋ถ„์„ portal ์•ˆ์— ๋„ฃ๊ณ  ์‹ถ์€๋ฐ ์–ด๋–ป๊ฒŒ ํ•ด์•ผํ• ๊นŒโ“

TestModal.js

์—ฌ๊ธฐ๋‹ค๊ฐ€ ์–ด๋””๋‹ค ๋„ฃ์„๊ฑด์ง€ ์ง€์ •ํ•ด์ฃผ๊ธฐ

์ด์   zIndex ์•ˆ ํŠ€์–ด๋‚˜์˜ค๋Š” ๊ฑธ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ์Œ๐Ÿ‘


๐ŸŒŸPortal ์“ฐ๋Š” ํŠน์ง• ํ•˜๋‚˜ ์žˆ์Œ

portal๋กœ ๋„ฃ์—ˆ๋‹ค ํ•˜๋”๋ผ๋„

์ € div ์š”์†Œ์˜ ์ž๋…€ ์š”์†Œ๋“ค์ž„

์ค‘์ฒฉ์ด ๋˜์–ด ์žˆ์Œ

๐Ÿงผ์ค‘์ฒฉ๋˜์–ด ์žˆ์œผ๋ฉด '์ด๋ฒคํŠธ ๋ฒ„๋ธ”๋ง' ์ผ์–ด๋‚ ๊นŒโ“

๋ฐ‘์—์„œ ์œ„๋กœ ์ž๋…€์—์„œ ๋ถ€๋ชจ๋กœ ํ•˜๋‚˜์”ฉ ํ•˜๋‚˜์”ฉ ํ•˜๋‚˜์”ฉ

์ด ์ž๋…€๋“ค์—์„œ ์ด๋ฒคํŠธ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ

์œ„๋กœ ๋ฒ„๋ธ”๋ง์ด ๋ฐœ์ƒํ• ๊นŒโ“ ์•ˆํ• ๊นŒโ“

โฃ ์ด๋ฒคํŠธ ๋ฒ„๋ธ”๋ง ๊ฐ€๋Šฅํ•จโžกportal์˜ ํŠน์ง•

<div style={modalWrapperStyle} 
  onClick={() => console.log('clicked')}>
  // ...

๐Ÿ–ฑApp.js ๋ถ€๋ชจ div์— ํด๋ฆญ ์ด๋ฒคํŠธ ๋„ฃ์–ด์คŒ

์ž๋…€ ํด๋ฆญํ•ด๋„ clicked๊ฐ€ ๋œธ ์ด๋ฒคํŠธ ๋ฒ„๋ธ”๋ง ๋˜๋Š” ๊ฑธ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ์Œ๐Ÿ™†โ€โ™€๏ธ

profile
์•ˆ๋…•ํ•˜์„ธ์š”! ํผ๋ธ”๋ฆฌ์‹ฑ & ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ ๊ณต๋ถ€ ๋ธ”๋กœ๊ทธ ์ž…๋‹ˆ๋‹ค!

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