[React] JSX์™€ Portals

deeยท2022๋…„ 10์›” 19์ผ
2

react

๋ชฉ๋ก ๋ณด๊ธฐ
3/6
post-thumbnail

๐Ÿค” JSX์™€ portals?

JSX? JS๋ฅผ ์˜๋ฏธํ•˜๋Š” ๊ฑด๊ฐ€? ๋’ค์— x๊ณผ ๋ถ™์€ ๊ฑด ๋ฌด์Šจ ์˜๋ฏธ์ผ๊นŒ ๊ถ๊ธˆํ•ด์ง„๋‹ค.
portals์€ react์—์„œ ์–ด๋–ป๊ฒŒ ์“ฐ์ด๊ณ  ์žˆ๋Š” ๊ฑธ๊นŒ? ์˜ค๋Š˜์˜ ๊ณต๋ถ€ ์ฃผ์ œ๋“ค์€ ํฅ๋ฏธ๋กญ๋‹ค.
์˜ˆ์‹œ๋ฅผ ํ•™์Šตํ•˜๋ฉฐ ๊ณต๋ถ€ํ•ด๋ณด๋„๋ก ํ•˜์ž.


JSX

  • UI๋ฅผ ๊ฐ€๋…์„ฑ์žˆ๊ฒŒ ์งค ์ˆ˜ ์žˆ๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋ฅผ ํ™•์žฅํ•œ ๋ฌธ๋ฒ•.
  • ํ•„์ˆ˜๋Š” ์•„๋‹ˆ์ง€๋งŒ ์‹œ๊ฐ์ ์œผ๋กœ html๊ณผ ๋น„์Šทํ•œ ๊ตฌ์กฐ์ด๊ธฐ ๋•Œ๋ฌธ์— ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š”๋ฐ ๋„์›€.
  • ํ‘œํ˜„์‹์ด๋ฏ€๋กœ ์กฐ๊ฑด๋ฌธ ์‚ฌ์šฉ ๊ฐ€๋Šฅ.
    ๐Ÿšจ return๋ฌธ ์•ˆ์—์„œ๋Š” ์‚ผํ•ญ ์—ฐ์‚ฐ์ž ๋˜๋Š” ๋…ผ๋ฆฌ ์—ฐ์‚ฐ์ž ์‚ฌ์šฉ.
  • ํƒœ๊ทธ๊ฐ€ ์ž์‹์„ ๊ฐ–์ง€ ์•Š๋Š”๋‹ค๋ฉด XML์ฒ˜๋Ÿผ ๋‹ซ๋Š” ํƒœ๊ทธ๋ฅผ ์‚ฌ์šฉ.
  • JSX๋ฅผ ํ† ๋Œ€๋กœ ์ปดํŒŒ์ผ๋˜์–ด React.createElement๋กœ ๋ณ€๊ฒฝ๋จ.
  • ๋…ผ๋ฆฌ์—ฐ์‚ฐ์ž ์‚ฌ์šฉ์‹œ ์ขŒํ•ญ์˜ ๊ฐ’์ด falsyํ•œ ํ‘œํ˜„์‹์ผ ๋•Œ ์šฐํ•ญ์˜ ํ‘œํ˜„์‹์€ ๋ฌด์‹œํ•˜์ง€๋งŒ falsyํ•œ ๊ฐ’์€ ํ‘œ์‹œ๋จ.
const App = () => {
  	const [loading, setLoading] = useState(true);
  	const [lang, setLang] = useState('ko')
  	
  	// ์กฐ๊ฑด๋ฌธ
  	if(loading) return <div>Loading....</div>;
	return (
    	<div>
      		// return๋ฌธ ์•ˆ์—์„œ๋Š” ์‚ผํ•ญ ๋˜๋Š” ๋…ผ๋ฆฌ ์—ฐ์‚ฐ์ž
      		{lang === 'ko'? '์•ˆ๋…•ํ•˜์„ธ์š”': 'Hello world'};
      
      		// ์ž์‹์„ ๊ฐ–์ง€ ์•Š์œผ๋ฏ€๋กœ ๋‹ซ๋Š” ํƒœ๊ทธ ์‚ฌ์šฉ
      		<input type="text"/>
      	</div>
    )
}

๐Ÿง JSX๋Š” ํ•˜๋‚˜์˜ root๋กœ ๊ฐ์‹ธ์ ธ์•ผ ๋˜๋Š” ์ด์œ ?
React.createElement๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ ๊ธฐ์ˆ ์ ์œผ๋กœ ํ•˜๋‚˜์˜ root๋งŒ ํ•„์š”ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
์•„๋ž˜ ์˜ˆ์‹œ์˜ div๊ฐ€ root๋ฅผ ์˜๋ฏธํ•œ๋‹ค.

React.createElement('div', null, 'Hello');

JSX์˜ div soup

return๋ฌธ ์•ˆ์—์„œ ํ•˜๋‚˜์˜ root๋กœ ๊ฐ์‹ธ์ ธ์•ผ ๋˜๋Š” ๊ธฐ์ˆ ์ ์ธ ์š”๊ตฌ๋กœ ์ธํ•ด react ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋‹ค๋ณด๋ฉด ์ˆ˜๋งŽ์€ div๊ฐ€ ์ค‘์ฒฉ๋˜๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. ์ด๋ฅผ div soup๋ผ๊ณ  ํ•œ๋‹ค.
์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•œ ๋ฐฉ๋ฒ•๋“ค์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

  1. ๋”ฐ๋กœ props๋ฅผ ๋ฐ›์•„ props.children๋งŒ ๋ฐ˜ํ™˜ํ•ด ์ฃผ๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ƒ์„ฑ.
    Wrapper ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋‘ ๊ฐœ์˜ Item ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ฐ˜ํ™˜.
// Wrapper.jsx
const Wrapper = (props) => {
	return props.children;
}

// App.jsx
const App = () => {
	return (
    	<Wrapper>
      		<Item />
      		<Item />
      	</Wrapper>
    )
}
  1. Fragment ์‚ฌ์šฉ. Fragment๋Š” ๋…ธ๋“œ๋ฅผ ๋”ฐ๋กœ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š๊ณ  ์ž์‹๋“ค์„ ๊ทธ๋ฃนํ™”.
    ๐Ÿงท <></>๋กœ๋„ Fragment๋ฅผ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ์Œ.
const App = () => {
	return (
    	<Fragment>
      		<Item />
      		<Item />
      	</Fragment>
    )
}

Portals

์‚ฌ์ „์ ์œผ๋กœ ๋‘ ๊ฐœ์˜ ์„œ๋กœ ๋‹ค๋ฅธ ์œ„์น˜๋ฅผ ์—ฐ๊ฒฐํ•˜๋Š” ๋งˆ๋ฒ•์ด๋‚˜ ๊ธฐ์ˆ ์ ์ธ ๋ฌธ์ด๋ผ๋Š” ์˜๋ฏธ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค. ์ด ๋œป ๊ทธ๋Œ€๋กœ Portals์€ react์—์„œ ๋‹ค๋ฅธ DOM ๋…ธ๋“œ๋กœ ์š”์†Œ๋ฅผ ๋ Œ๋”๋งํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ค€๋‹ค. Portals ์“ฐ์ง€ ์•Š์•„๋„ ๋ฌธ์ œ๊ฐ€ ๋˜์ง€ ์•Š์ง€๋งŒ ์ ‘๊ทผ์„ฑ ์ธก๋ฉด์—์„œ๋‚˜ ์‹œ๋ฉ˜ํ‹ฑ ๊ด€์ ์—์„œ๋Š” ์ข‹์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์ด ์ ์„ ๊ณ ๋ คํ•ด์„œ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

๐Ÿ“์œ„์˜ ๊ฐœ๋…์„ ๊ฐ€์žฅ ์ž˜ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์€ Modal๋กœ ์˜ˆ์‹œ๋ฅผ ํ†ตํ•ด ์•Œ์•„๋ณด์ž.

  1. index.html์— id๊ฐ€ root์ธ div์ด์™ธ์— div๋ฅผ ํ•˜๋‚˜ ๋” ์ƒ์„ฑํ•œ๋‹ค.
  2. div์— id="modal__root"๋ฅผ ์ง€์ •.
	<!--index.html-->
	<body>
		<div id="modal__root"></div> <!--๋ชจ๋‹ฌ์ด ๋“ค์–ด๊ฐ€๋Š” root-->
      	<div id="root"></div>
	</body>
  1. Modal ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ƒ์„ฑ.
  2. Modal ์ปดํฌ๋„ŒํŠธ๋ฅผ portalํ•  ์ˆ˜ ์žˆ๋„๋ก WarningModal ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ƒ์„ฑ.
  3. WarningModal ์ปดํฌ๋„ŒํŠธ์—์„œ createPortalํ•จ์ˆ˜ ํ˜ธ์ถœ.
    ๐Ÿงท React.createPortal(์ „๋‹ฌํ•  ์ปดํฌ๋„ŒํŠธ, ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ๋˜๋Š” DOM ๋…ธ๋“œ)
    ๐Ÿšจ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ „๋‹ฌํ•  ๋•Œ props๋„ ๊ฐ™์ด ๋„˜๊ฒจ์ฃผ์–ด์•ผ ํ•จ.
	// Modal.jsx
	const Modal = props => {
    	return (
          <>
          	<div className="dimmed__layer" onClick={props.onConfirm}></div>
          	<div className="modal__body">{props.title}</div>
          </>
        )
    }
    
    const WarningModal = props => {
    	return (
        	<>
          {React.createPortal(<Modal title={props.title} onConfirm={props.onConfirm}/>, document.querySelector('#modal__root'))}
          	</>
        )
    }
  1. ์ƒํƒœ๊ฐ’์— ๋”ฐ๋ผ WarningModal์ด ๋ณด์ด๋„๋ก ํ•จ.
// App.jsx
const App = () => {
	const [isShowModal, setIsShowModal] = useState(false);
  	const onConfirm = () => setIsShowModal(false);
    
	return (
    	<>
      		{isShowModal && <WarningModal title="warning" onConfirm={onConfirm}/>}
      		<Item />
      		<Item />
      	</>
    )
}

๐Ÿ‘ ์˜ค๋Š˜์˜ ๊ณต๋ถ€์ผ๊ธฐ

react๋ฅผ ๊ณต๋ถ€ํ•˜๋ฉด์„œ ์ปดํฌ๋„ŒํŠธํ™”์— ๋” ์ง‘์ค‘ํ•˜๋Š” ๊ฒฝํ–ฅ์ด ์žˆ์—ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‹ค๋ณด๋‹ˆ ์ ‘๊ทผ์„ฑ๊ณผ ์‹œ๋ฉ˜ํ‹ฑ ๋งˆํฌ์—…์— ๋Œ€ํ•ด ์‹ ๊ฒฝ์“ฐ์ง€ ๋ชปํ–ˆ๊ณ  ์ œ๋Œ€๋กœ ์˜๋ฏธ๋ฅผ ๊ฐ–๋„๋ก ๋งˆํฌ์—…ํ•˜๋Š” ๊ฒƒ์ด ์–ด๋ ค์› ๋‹ค. ์ด๋Ÿฐ ๋ฌธ์ œ์ ๋“ค์„ createPortal์ด๋ผ๋Š” ๊ฒƒ์„ ํ†ตํ•ด์„œ ํ•œ๋ฒˆ์— ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค๋‹ˆ ์‹ ์„ธ๊ณ„์˜€๋‹ค. Modal์„ ๋ฐ˜๋ณตํ•™์Šตํ•˜๋ฉด์„œ portal์— ๋Œ€ํ•ด ์ต์ˆ™ํ•ด์ง€๊ณ  ์‹œ๋ฉ˜ํ‹ฑ ๋งˆํฌ์—…์„ ์œ„ํ•ด ๋” ๊นŠ๊ฒŒ ์ƒ๊ฐ์„ ํ•ด์•ผ๊ฒ ๋‹ค.


์ฐธ๊ณ  ์ž๋ฃŒ
https://ko.reactjs.org/docs/portals.html

profile
์›น ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์ž

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