React: createPortal: React ํŠธ๋ฆฌ์—์„œ ์ด๋ฒคํŠธ ์ „ํŒŒ๋ฅผ ์ค‘์ง€ํ•˜๋Š” ์ง€์› ์˜ต์…˜

์— ๋งŒ๋“  2017๋…„ 10์›” 27์ผ  ยท  103์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: facebook/react

๊ธฐ๋Šฅ ์„ ์š”์ฒญํ•˜๊ฑฐ๋‚˜ ๋ฒ„๊ทธ๋ฅผ ๋ณด๊ณ  ํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?
๊ธฐ๋Šฅ์ด์ง€๋งŒ ์ƒˆ API๊ฐ€ ์ด์ „ unstable_rendersubtreeintocontainer ์ค‘๋‹จ์‹œํ‚ค๋Š” ๋ฒ„๊ทธ๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ˜„์žฌ ํ–‰๋™์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?
ํฌํ„ธ์—์„œ React ํŠธ๋ฆฌ ์กฐ์ƒ์œผ๋กœ์˜ ๋ชจ๋“  ์ด๋ฒคํŠธ ์ „ํŒŒ๋ฅผ ๋ฉˆ์ถœ ์ˆ˜๋Š” ์—†์Šต๋‹ˆ๋‹ค. ๋ชจ๋‹ฌ/ํŒ์˜ค๋ฒ„๊ฐ€ ์žˆ๋Š” ๋ ˆ์ด์–ด ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด ์™„์ „ํžˆ ์†์ƒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋“œ๋กญ๋‹ค์šด ๋ฒ„ํŠผ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ํด๋ฆญํ•˜๋ฉด ํŒ์˜ค๋ฒ„๊ฐ€ ์—ด๋ฆฝ๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ๋˜ํ•œ ๊ฐ™์€ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•  ๋•Œ ์ด ํŒ์˜ค๋ฒ„๋ฅผ ๋‹ซ๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. createPortal์„ ์‚ฌ์šฉํ•˜์—ฌ ํŒ์˜ค๋ฒ„ ๋‚ด๋ถ€๋ฅผ ํด๋ฆญํ•˜๋ฉด ๋ฒ„ํŠผ์ด ํด๋ฆญ๋˜๊ณ  ๋‹ซํž™๋‹ˆ๋‹ค. ์ด ๊ฐ„๋‹จํ•œ ๊ฒฝ์šฐ์— stopPropagation์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์šฐ๋ฆฌ๋Š” ๊ทธ๋Ÿฌํ•œ ๊ฒฝ์šฐ๊ฐ€ ๋งŽ๊ณ  ๋ชจ๋“  ๊ฒฝ์šฐ์— stopPropagation์„ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ๋ชจ๋“  ์ด๋ฒคํŠธ๋ฅผ ์ค‘์ง€ํ•  ์ˆ˜๋Š” ์—†์Šต๋‹ˆ๋‹ค.

์˜ˆ์ƒ๋˜๋Š” ๋™์ž‘์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?
createPortal์—๋Š” ๋ชจ๋“  ์ด๋ฒคํŠธ๋ฅผ ์ˆ˜๋™์œผ๋กœ ์ค‘์ง€ํ•˜์ง€ ์•Š๊ณ  React ํŠธ๋ฆฌ๋ฅผ ํ†ตํ•œ ํ•ฉ์„ฑ ์ด๋ฒคํŠธ ์ „ํŒŒ๋ฅผ ์ค‘์ง€ํ•˜๋Š” ์˜ต์…˜์ด ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์–ด๋–ป๊ฒŒ ์ƒ๊ฐํ•˜๋‚˜์š”?

DOM Feature Request

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

๊ทธ๋งˆ์ €๋„ ๋‚˜์—๊ฒŒ๋Š” ๋ถˆํ•„์š”ํ•˜๊ฒŒ ๋ณต์žกํ•ด ๋ณด์ธ๋‹ค. ๋ฒ„๋ธ”๋ง ๋™์ž‘์„ ์ฐจ๋‹จํ•  ์ˆ˜ ์žˆ๋„๋ก createPortal์— ์„ ํƒ์  ๋ถ€์šธ ํ”Œ๋ž˜๊ทธ๋ฅผ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š๋Š” ์ด์œ ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

๋ชจ๋“  103 ๋Œ“๊ธ€

๋˜ํ•œ mouseOver/Leave์˜ ์ „ํŒŒ๋Š” ์™„์ „ํžˆ ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ž…๋‹ˆ๋‹ค.
image

ํฌํ„ธ์„ ๋ฒ„ํŠผ ๋ฐ–์œผ๋กœ ์ด๋™ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

์˜ˆ

return [
  <div key="main">
    <p>Hello! This is first step.</p>
    <Button key="button" />
  </div>,
  <Portal key="portal" />
];

๊ทธ๋Ÿฌ๋ฉด ๋ฒ„ํŠผ์„ ํ†ตํ•ด ๊ฑฐํ’ˆ์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋‚ด ์ฒซ ๋ฒˆ์งธ ์ƒ๊ฐ์ด์—ˆ์ง€๋งŒ!) ์ด๋Ÿฌํ•œ ๊ตฌ์„ฑ ์š”์†Œ ์ปจํ…Œ์ด๋„ˆ์— mouseEnter ์ฒ˜๋ฆฌ๊ธฐ๊ฐ€ ์žˆ๋‹ค๊ณ  ์ƒ์ƒํ•ด๋ณด์‹ญ์‹œ์˜ค.

image

ํ•จ๊ป˜ unstable_rendersubtreeintocontainer ๋‚ด๊ฐ€ ํ•„์š” ์•„๋ฌด๊ฒƒ๋„์˜ ์ด๋ฒคํŠธ์™€๋Š” ButtonWithPopover ๊ตฌ์„ฑ ์š”์†Œ - ๋งˆ์šฐ์Šค๊ฐ€ ์ •๋ง ๋“ค์–ด๊ฐˆ ๋•Œ mouseEnter ๋‹จ์ˆœํžˆ ์ž‘๋™ div ๋ฒ„ํŠผ์˜ DOM ์š”์†Œ๋ฅผ, ๋งˆ์šฐ์Šค๊ฐ€ ํŒ ์˜ค๋ฒ„ ์œ„์—์žˆ์„ ๋•Œ ํ•ด๊ณ  ์—†์Šต๋‹ˆ๋‹ค. ํฌํ„ธ์„ ์‚ฌ์šฉํ•˜๋ฉด ํŒ์˜ค๋ฒ„ ์œ„๋กœ ๋งˆ์šฐ์Šค๋ฅผ ๊ฐ€์ ธ๊ฐ€๋ฉด ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ์ด ์ˆœ๊ฐ„์—๋Š” ์‹ค์ œ๋กœ div ๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ „ํŒŒ๋ฅผ ์ค‘๋‹จํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ButtonWithPopover ๊ตฌ์„ฑ ์š”์†Œ์—์„œ ์ˆ˜ํ–‰ํ•˜๋ฉด ๋งˆ์šฐ์Šค๊ฐ€ ๋ฒ„ํŠผ ์œ„์— ์žˆ์„ ๋•Œ ์ด๋ฒคํŠธ ๋ฐœ์ƒ์ด ์ค‘๋‹จ๋ฉ๋‹ˆ๋‹ค. ํŒ์˜ค๋ฒ„์—์„œ ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๊ณ  ์ด ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์— ๋Œ€ํ•ด ๋ช‡ ๊ฐ€์ง€ ์ผ๋ฐ˜์ ์ธ ํŒ์˜ค๋ฒ„ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ๋‹ค๋ฅธ ์•ฑ ๋ถ€๋ถ„์—์„œ ๋…ผ๋ฆฌ๋ฅผ ์ค‘๋‹จํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” React ํŠธ๋ฆฌ๋ฅผ ํ†ตํ•ด ๋ฒ„๋ธ” ๋งํ•˜๋Š” ๋ชฉ์ ์„ ์ •๋ง๋กœ ์ดํ•ดํ•˜์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค. ํฌํ„ธ ๊ตฌ์„ฑ ์š”์†Œ์—์„œ ์ด๋ฒคํŠธ๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ โ€“ ๋‹จ์ˆœํžˆ props๋ฅผ ํ†ตํ•ด ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” unstable_rendersubtreeintocontainer ๋กœ ๊ทธ๊ฒƒ์„ ํ–ˆ๊ณ  ์™„๋ฒฝํ•˜๊ฒŒ ์ž‘๋™ํ–ˆ์Šต๋‹ˆ๋‹ค.

๋ฐ˜์‘ ํŠธ๋ฆฌ์˜ ๊นŠ์ˆ™ํ•œ ์ผ๋ถ€ ๋ฒ„ํŠผ์—์„œ ๋ชจ๋‹ฌ ์ฐฝ์„ ์—ด๋ฉด ๋ชจ๋‹ฌ์—์„œ ์˜ˆ๊ธฐ์น˜ ์•Š์€ ์ด๋ฒคํŠธ ๋ฐœ์ƒ์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. stopPropagation ๋„ DOM์—์„œ ์ „ํŒŒ๋ฅผ ์ค‘์ง€ํ•˜๊ณ  ์‹ค์ œ๋กœ ํ•ด๊ณ ๋  ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒ๋˜๋Š” ์ด๋ฒคํŠธ๋ฅผ ์–ป์ง€ ๋ชปํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค(

@gaearon ๋‚˜๋Š” ์ด๊ฒƒ์ด ๊ธฐ๋Šฅ ์š”์ฒญ๋ณด๋‹ค ๋” ๋งŽ์€ ๋ฒ„๊ทธ๋ผ๊ณ  ์ œ์•ˆํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. ํฌํ„ธ(์ด์ „์— unstable_rendersubtreeintocontainer ์‚ฌ์šฉํ–ˆ๋˜ ๊ณณ)์„ ํ†ตํ•ด ๋ฐœ์ƒํ•˜๋Š” ๋งˆ์šฐ์Šค ์ด๋ฒคํŠธ๋กœ ์ธํ•ด ๋ฐœ์ƒํ•˜๋Š” ์ƒˆ๋กœ์šด ๋ฒ„๊ทธ๊ฐ€ ๋งŽ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋“ค ์ค‘ ์ผ๋ถ€๋Š” ๋งˆ์šฐ์Šค ์ด๋ฒคํŠธ๋ฅผ ํ•„ํ„ฐ๋งํ•˜๊ธฐ ์œ„ํ•œ ์ถ”๊ฐ€ div ๋ ˆ์ด์–ด๋กœ๋„ ์ˆ˜์ •ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋“œ๋ž˜๊ทธ ๊ฐ€๋Šฅํ•œ ๋Œ€ํ™” ์ƒ์ž๋ฅผ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ๋ฌธ์„œ๋กœ ์ „ํŒŒ๋˜๋Š” mousemove ์ด๋ฒคํŠธ์— ์˜์กดํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

ํ–ฅํ›„ ๋ฆด๋ฆฌ์Šค์—์„œ ์ด ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋˜๊ธฐ ์ „์— ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๊นŒ?

ํฌํ„ธ์˜ ํ˜„์žฌ ๊ฑฐํ’ˆ ๋™์ž‘์ด ์˜ˆ์ƒ๋˜๊ณ  ์˜๋„๋œ ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— ๊ธฐ๋Šฅ ์š”์ฒญ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋ชฉํ‘œ๋Š” ํ•˜์œ„ ํŠธ๋ฆฌ๊ฐ€ ๋ถ€๋ชจ์˜ ์‹ค์ œ ์ž์‹์ฒ˜๋Ÿผ ์ž‘๋™ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋„์›€์ด ๋˜๋Š” ๊ฒƒ์€ ํ˜„์žฌ ๊ตฌํ˜„์—์„œ ์ œ๊ณต๋˜์ง€ ์•Š๊ฑฐ๋‚˜ ํ•ด๊ฒฐํ•˜๊ธฐ ์–ด๋ ค์šด ์ถ”๊ฐ€ ์‚ฌ์šฉ ์‚ฌ๋ก€ ๋˜๋Š” ์ƒํ™ฉ(์ง€๊ธˆ ๋ณด๊ณ  ์žˆ๋Š” ๊ฒƒ๊ณผ ๊ฐ™์€)์ž…๋‹ˆ๋‹ค.

์ด ๋™์ž‘์ด ์˜๋„๋œ ๊ฒƒ์ž„์„ ์ดํ•ดํ•˜์ง€๋งŒ ๋น„ํ™œ์„ฑํ™”ํ•  ์ˆ˜ ์—†๋Š” ์ค‘์š”ํ•œ ๋ฒ„๊ทธ๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๋‚ด ๋งˆ์Œ์— DOM์œผ๋กœ ์ž‘์—…ํ•˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” DOM ๊ตฌํ˜„ ๋™์ž‘์„ ์†์ƒ์‹œํ‚ค์ง€ ์•Š๊ณ  ๋ณด์กดํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด:

class Container extends React.Component {
  shouldComponentUpdate = () => false;
  render = () => (
    <div
      ref={this.props.containerRef}
      // Event propagation on this element not working
      onMouseEnter={() => { console.log('handle mouse enter'); }}
      onClick={() => { console.log('handle click'); }}
    />
  )
}

class Root extends React.PureComponent {
  state = { container: null };
  handleContainer = (container) => { this.setState({ container }); }

  render = () => (
    <div>
      <div
        // Event propagation on this element not working also
        onMouseEnter={() => { console.log('handle mouse enter'); }}
        onClick={() => { console.log('handle click'); }}
      >
        <Container containerRef={this.handleContainer} />
      </div>
      {this.state.container && ReactDOM.createPortal(
        <div>Portal</div>,
        this.state.container
      )}
    </div>
  );
}

DOM์œผ๋กœ ์ž‘์—…ํ•  ๋•Œ DOM ๊ตฌํ˜„๊ณผ ๊ฐ™์€ ์ด๋ฒคํŠธ๋ฅผ ์ˆ˜์‹ ํ•  ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒํ•ฉ๋‹ˆ๋‹ค. ๋‚ด ์˜ˆ์ œ์—์„œ ์ด๋ฒคํŠธ๋Š” Portal ์„ ํ†ตํ•ด ์ „ํŒŒ๋˜๊ณ  DOM ๋ถ€๋ชจ๋ฅผ ์šฐํšŒํ•˜๋ฉฐ ์ด๋Š” ๋ฒ„๊ทธ ๋กœ ๊ฐ„์ฃผ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ† ๋ก ์„ ํ•ด์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋ฒ„๊ทธ์ธ์ง€ ์•„๋‹Œ์ง€๋ฅผ ๋…ผํ•˜๋Š” ๊ฒƒ์€ ๊ทธ๋‹ค์ง€ ๋„์›€์ด ๋˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋Œ€์‹  ํ˜„์žฌ ๋™์ž‘์œผ๋กœ ์ถฉ์กฑ๋˜์ง€ ์•Š๋Š” ์‚ฌ์šฉ ์‚ฌ๋ก€์™€ ์˜ˆ๋ฅผ ๋…ผ์˜ํ•˜๋Š” ๊ฒƒ์ด ๋” ์ƒ์‚ฐ์ ์ด๋ฏ€๋กœ ํ˜„์žฌ ๋ฐฉ์‹์ด ๋ฏธ๋ž˜๋ฅผ ์œ„ํ•œ ์ตœ์„ ์˜ ๋ฐฉ๋ฒ•์ธ์ง€ ๋” ์ž˜ ์ดํ•ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ผ๋ฐ˜์ ์œผ๋กœ ์šฐ๋ฆฌ๋Š” API๊ฐ€ ๋‹ค๋ฅธ ์‚ฌ์šฉ ์‚ฌ๋ก€๋ฅผ ๊ณผ๋„ํ•˜๊ฒŒ ์ œํ•œํ•˜์ง€ ์•Š์œผ๋ฉด์„œ ๋‹ค์–‘ํ•œ ์‚ฌ์šฉ ์‚ฌ๋ก€๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค. ํ•ต์‹ฌ ํŒ€์— ๋Œ€ํ•ด ๋งํ•  ์ˆ˜๋Š” ์—†์ง€๋งŒ ๊ตฌ์„ฑ ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ๊ฒƒ์€ ๊ฐ€๋Šฅํ•œ ์†”๋ฃจ์…˜์ด ์•„๋‹ˆ๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ React๋Š” ๊ตฌ์„ฑ ๊ฐ€๋Šฅํ•œ API๋ณด๋‹ค ์ผ๊ด€๋œ API๋ฅผ ์„ ํ˜ธํ•ฉ๋‹ˆ๋‹ค.

๋‚˜๋Š” ๋˜ํ•œ ์ด ๋™์ž‘์ด DOM์ด ์ž‘๋™ํ•˜๋Š” ๋ฐฉ์‹์ด ์•„๋‹ˆ๋ผ๋Š” ๊ฒƒ์„ ์ดํ•ดํ•˜์ง€๋งŒ, ๊ทธ ์ž์ฒด๋กœ ๊ทธ๋ ‡๊ฒŒ ๋˜์–ด์„œ๋Š” ์•ˆ ๋œ๋‹ค๊ณ  ๋งํ•  ์ข‹์€ ์ด์œ ๋Š” ์•„๋‹ˆ๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. react-dom์˜ ๋งŽ์€ ๋™์ž‘์€ DOM์ด ์ž‘๋™ํ•˜๋Š” ๋ฐฉ์‹๊ณผ ๋‹ค๋ฅด๋ฉฐ ์ด๋ฒคํŠธ๊ฐ€ ์ด๋ฏธ ๊ธฐ๋ณธ ๋ฒ„์ „๊ณผ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด onChange ๋Š” ๊ธฐ๋ณธ ๋ณ€๊ฒฝ ์ด๋ฒคํŠธ์™€ ์™„์ „ํžˆ ๋‹ค๋ฅด๋ฉฐ DOM๊ณผ ๋‹ฌ๋ฆฌ ๋ชจ๋“  ๋ฐ˜์‘ ์ด๋ฒคํŠธ๋Š” ์œ ํ˜•์— ๊ด€๊ณ„์—†์ด ๋ฒ„๋ธ”๋ง๋ฉ๋‹ˆ๋‹ค.

๋Œ€์‹  ํ˜„์žฌ ๋™์ž‘์œผ๋กœ ์ถฉ์กฑ๋˜์ง€ ์•Š๋Š” ์‚ฌ์šฉ ์‚ฌ๋ก€์™€ ์˜ˆ๋ฅผ ๋…ผ์˜ํ•˜๋Š” ๊ฒƒ์ด ๋” ์ƒ์‚ฐ์ ์ž…๋‹ˆ๋‹ค.

๋‹ค์Œ์€ React 16์œผ๋กœ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ํ•  ๋•Œ ๊นจ์ง„ ๋‘ ๊ฐ€์ง€ ์˜ˆ์ž…๋‹ˆ๋‹ค.

๋จผ์ € ๋ฒ„ํŠผ์œผ๋กœ ์‹คํ–‰๋˜๋Š” ๋“œ๋ž˜๊ทธ ๊ฐ€๋Šฅํ•œ ๋Œ€ํ™” ์ƒ์ž๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ชจ๋“  ๋งˆ์šฐ์Šค* ํ‚ค* ์ด๋ฒคํŠธ์— ๋Œ€ํ•ด StopPropagation์„ ํ˜ธ์ถœํ•˜๋Š” ํฌํ„ธ ์‚ฌ์šฉ์— "ํ•„ํ„ฐ๋ง" ์š”์†Œ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ ค๊ณ  ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋“œ๋ž˜๊ทธ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ๋ฌธ์„œ์— mousemove ์ด๋ฒคํŠธ๋ฅผ ๋ฐ”์ธ๋”ฉํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ๋งˆ์šฐ์Šค๋ฅผ ์ƒ๋‹นํ•œ ์†๋„๋กœ ์›€์ง์ด๋ฉด ์ปค์„œ๊ฐ€ ๋Œ€ํ™” ์ƒ์ž์˜ ๊ฒฝ๊ณ„๋ฅผ ๋ฒ—์–ด๋‚˜๊ธฐ ๋•Œ๋ฌธ์— ์ผ๋ฐ˜์ ์ž…๋‹ˆ๋‹ค. ๋” ๋†’์€ ์ˆ˜์ค€์—์„œ ๋งˆ์šฐ์Šค ์›€์ง์ž„์„ ์บก์ฒ˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์ด๋ฒคํŠธ๋ฅผ ํ•„ํ„ฐ๋งํ•˜๋ฉด ์ด ๊ธฐ๋Šฅ์ด ์ค‘๋‹จ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ Portal์„ ์‚ฌ์šฉํ•˜๋ฉด ๋งˆ์šฐ์Šค ๋ฐ ํ‚ค ์ด๋ฒคํŠธ๊ฐ€ ๋Œ€ํ™” ์ƒ์ž ๋‚ด๋ถ€์—์„œ ์ด๋ฅผ ์‹คํ–‰ํ•œ ๋ฒ„ํŠผ์œผ๋กœ ๋ฒ„๋ธ”๋ง๋˜์–ด ๋‹ค๋ฅธ ์‹œ๊ฐ ํšจ๊ณผ๋ฅผ ํ‘œ์‹œํ•˜๊ณ  ๋Œ€ํ™” ์ƒ์ž๋ฅผ ๋‹ซ๊ฒŒ ๋งŒ๋“ค ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ํฌํ„ธ์„ ํ†ตํ•ด ์‹œ์ž‘๋  ๋ชจ๋“  ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ์ด ์ด๋ฒคํŠธ ์ „ํŒŒ๋ฅผ ์ค‘์ง€ํ•˜๊ธฐ ์œ„ํ•ด 10-20๊ฐœ์˜ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ๋ฐ”์ธ๋”ฉํ•˜๋Š” ๊ฒƒ์ด ํ˜„์‹ค์ ์ด์ง€ ์•Š๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

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

ํ•ต์‹ฌ ํŒ€์— ๋Œ€ํ•ด ๋งํ•  ์ˆ˜๋Š” ์—†์ง€๋งŒ ๊ตฌ์„ฑ ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ๊ฒƒ์€ ๊ฐ€๋Šฅํ•œ ์†”๋ฃจ์…˜์ด ์•„๋‹ˆ๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ React๋Š” ๊ตฌ์„ฑ ๊ฐ€๋Šฅํ•œ API๋ณด๋‹ค ์ผ๊ด€๋œ API๋ฅผ ์„ ํ˜ธํ•ฉ๋‹ˆ๋‹ค.

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

๋‚˜๋Š” ๋˜ํ•œ ์ด ๋™์ž‘์ด DOM์ด ์ž‘๋™ํ•˜๋Š” ๋ฐฉ์‹์ด ์•„๋‹ˆ๋ผ๋Š” ๊ฒƒ์„ ์ดํ•ดํ•˜์ง€๋งŒ, ๊ทธ ์ž์ฒด๋กœ ๊ทธ๋ ‡๊ฒŒ ๋˜์–ด์„œ๋Š” ์•ˆ ๋œ๋‹ค๊ณ  ๋งํ•  ์ข‹์€ ์ด์œ ๋Š” ์•„๋‹ˆ๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๋‚˜๋Š” ๋‹น์‹ ์ด ์—ฌ๊ธฐ์—์„œ ์˜ค๋Š” ๊ฒƒ์„ ์ดํ•ดํ•˜์ง€๋งŒ ์ด ๊ฒฝ์šฐ (a) ์ด๊ฒƒ์€ (b) ํ˜„์žฌ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์ด ์—†๋Š” ๊ทผ๋ณธ์ ์ธ ๋™์ž‘์ด๋ฏ€๋กœ "DOM์ด ์ด๋Ÿฐ ์‹์œผ๋กœ ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค"๋ผ๋Š” ๊ฐ•๋ ฅํ•œ ์ฃผ์žฅ์ด ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์™„์ „ํžˆ ์„ค๋“๋ ฅ์ด ์—†๋‹ค๋ฉด.

๊ทธ๋ฆฌ๊ณ  ๋ถ„๋ช…ํžˆ ๋ง์”€๋“œ๋ฆฌ์ž๋ฉด, ์ด๊ฒƒ์„ ๋ฒ„๊ทธ๋กœ ๊ฐ„์ฃผํ•ด ๋‹ฌ๋ผ๋Š” ์ œ ์š”์ฒญ์€ ๋Œ€๋ถ€๋ถ„ ๋‚˜์ค‘์—๋ณด๋‹ค ๋นจ๋ฆฌ ์ˆ˜์ •์„ ์œ„ํ•ด ์šฐ์„  ์ˆœ์œ„๋ฅผ ์ง€์ •ํ•˜๊ธฐ ์œ„ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

Portal์— ๋Œ€ํ•œ ์ œ ๋ฉ˜ํƒˆ ๋ชจ๋ธ์€ ๋งˆ์น˜ ํŠธ๋ฆฌ์˜ ๊ฐ™์€ ์œ„์น˜์— ์žˆ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ์ž‘๋™ํ•˜์ง€๋งŒ "์˜ค๋ฒ„ํ”Œ๋กœ: ์ˆจ๊น€"๊ณผ ๊ฐ™์€ ๋ฌธ์ œ๋ฅผ ํ”ผํ•˜๊ณ  ๊ทธ๋ฆฌ๊ธฐ/๋ ˆ์ด์•„์›ƒ ๋ชฉ์ ์œผ๋กœ ์Šคํฌ๋กคํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

ํฌํ„ธ ์—†์ด ์ธ๋ผ์ธ์œผ๋กœ ๋ฐœ์ƒํ•˜๋Š” ์œ ์‚ฌํ•œ "ํŒ์—…" ์†”๋ฃจ์…˜์ด ๋งŽ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ: ๋ฐ”๋กœ ์˜†์— ์žˆ๋Š” ์ƒ์ž๋ฅผ ํ™•์žฅํ•˜๋Š” ๋ฒ„ํŠผ.

์—ฌ๊ธฐ GitHub์—์„œ "๋ฐ˜์‘ ์„ ํƒ" ๋Œ€ํ™” ์ƒ์ž๋ฅผ ์˜ˆ๋กœ ๋“ค์–ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๋ฒ„ํŠผ ๋ฐ”๋กœ ์˜†์— div๋กœ ๊ตฌํ˜„๋ฉ๋‹ˆ๋‹ค. ์ง€๊ธˆ์€ ์ž˜ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋‹ค๋ฅธ z-์ƒ‰์ธ์„ ๊ฐ–๊ฑฐ๋‚˜ ์ด๋Ÿฌํ•œ ์ฃผ์„์ด ํฌํ•จ๋œ overflow: scroll ์˜์—ญ์—์„œ ์ œ๊ฑฐํ•˜๋ ค๋ฉด DOM ์œ„์น˜๋ฅผ ๋ณ€๊ฒฝํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฒคํŠธ ๋ฒ„๋ธ”๋ง๊ณผ ๊ฐ™์€ ๋‹ค๋ฅธ ํ•ญ๋ชฉ๋„ ๋ณด์กด๋˜์ง€ ์•Š๋Š” ํ•œ ํ•ด๋‹น ๋ณ€๊ฒฝ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์ด ์•ˆ์ „ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

"ํŒ์—…" ๋˜๋Š” "ํŒ์•„์›ƒ"์˜ ๋‘ ๊ฐ€์ง€ ์Šคํƒ€์ผ์€ ๋ชจ๋‘ ํ•ฉ๋ฒ•์ž…๋‹ˆ๋‹ค. ๊ทธ๋ ‡๋‹ค๋ฉด ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ๋ ˆ์ด์•„์›ƒ ์™ธ๋ถ€์— ๋–  ์žˆ๋Š” ๊ฒƒ๊ณผ ๋Œ€์กฐ์ ์œผ๋กœ ๋ ˆ์ด์•„์›ƒ์— ์ธ๋ผ์ธ์ธ ๊ฒฝ์šฐ ๋™์ผํ•œ ๋ฌธ์ œ๋ฅผ ์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

๋‚˜๋ฅผ ์œ„ํ•ด ์ผํ•œ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์€ ํฌํ„ธ ๋ Œ๋”๋ง์—์„œ ์ง์ ‘ stopPropagation ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

return createPortal(
      <div onClick={e => e.stopPropagation()}>{this.props.children}</div>,
      this.el
    )

ํฌํ„ธ์„ ์‚ฌ์šฉํ•˜๋Š” ๋‹จ์ผ ์ถ”์ƒํ™” ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ €์—๊ฒŒ ํšจ๊ณผ์ ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ๋ชจ๋“  createPortal ํ˜ธ์ถœ์„ ์ˆ˜์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

@methyl ์ด๊ฒƒ์€ ํŠธ๋ฆฌ๋ฅผ ๋ฒ„๋ธ”๋งํ•˜์ง€ ๋ชปํ•˜๋„๋ก ์ฐจ๋‹จํ•ด์•ผ ํ•˜๋Š” ๋ชจ๋“  ์ด๋ฒคํŠธ๋ฅผ ์•Œ๊ณ  ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋“œ๋ž˜๊ทธ ๋Œ€ํ™” ์ƒ์ž์— ์–ธ๊ธ‰ ๋œ ๊ฒฝ์šฐ์—, ์šฐ๋ฆฌ๋Š” ํ•„์š” mousemove ๋ฌธ์„œ์— ๊ฑฐํ’ˆ๊นŒ์ง€๊ฐ€ ์•„๋‹ˆ๋ผ ๋ Œ๋”๋ง ๋‚˜๋ฌด ์œ„๋กœ ๊ฑฐํ’ˆ์—.

"ํŒ์—…" ๋˜๋Š” "ํŒ์•„์›ƒ"์˜ ๋‘ ๊ฐ€์ง€ ์Šคํƒ€์ผ์€ ๋ชจ๋‘ ํ•ฉ๋ฒ•์ž…๋‹ˆ๋‹ค. ๊ทธ๋ ‡๋‹ค๋ฉด ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ๋ ˆ์ด์•„์›ƒ ์™ธ๋ถ€์— ๋–  ์žˆ๋Š” ๊ฒƒ๊ณผ ๋Œ€์กฐ์ ์œผ๋กœ ๋ ˆ์ด์•„์›ƒ์— ์ธ๋ผ์ธ์ธ ๊ฒฝ์šฐ ๋™์ผํ•œ ๋ฌธ์ œ๋ฅผ ์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

@sebmarkbage ์ด ์งˆ๋ฌธ์ด ์˜๋ฏธ๊ฐ€ ์žˆ๋Š”์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค. ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์ธ๋ผ์ธํ•˜๋Š” ๋ฐ ์ด ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ์ธ๋ผ์ธํ•˜์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์—ฌ๊ธฐ ๋ฌธ์ œ ์ค‘ ์ผ๋ถ€์˜ ๋ช‡ ๊ฐ€์ง€ ์‚ฌ์šฉ ์‚ฌ๋ก€๋ผ๊ณ  ์ƒ๊ฐ renderSubtreeIntoContainer ์— ์ด์‹๋˜๊ณ ์žˆ๋‹ค createPortal ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์€ ๊ฐœ๋…์ ์œผ๋กœ ๋‹ค๋ฅธ ์ผ์„ ํ•  ๋•Œ. Portal์˜ ๊ฐœ๋…์ด ๊ณผ๋ถ€ํ•˜๊ฐ€ ๊ฑธ๋ฆฐ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ๋ชจ๋‹ฌ ๋Œ€ํ™” ์ƒ์ž์˜ ๊ฒฝ์šฐ ๋ชจ๋‹ฌ์ด ๊ทธ๊ฒƒ์„ ์—ฐ ๋ฒ„ํŠผ์˜ ์ž์‹์ฒ˜๋Ÿผ ์ž‘๋™ํ•˜๋Š” ๊ฒƒ์„ ๊ฑฐ์˜ ์›ํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๋ฐ ๋™์˜ํ•ฉ๋‹ˆ๋‹ค. ํŠธ๋ฆฌ๊ฑฐ ๊ตฌ์„ฑ ์š”์†Œ๋Š” open ์ƒํƒœ๋ฅผ ์ œ์–ดํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ Œ๋”๋ง๋งŒ ํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋ฒ„ํŠผ์˜ createPortal ๊ฐ€ ์ด์— ๋Œ€ํ•œ ์˜ฌ๋ฐ”๋ฅธ ๋„๊ตฌ๊ฐ€ ์•„๋‹ˆ๋ผ๊ณ  ๋งํ•˜๋Š” ๋Œ€์‹  ํฌํ„ธ ๊ตฌํ˜„์ด ์ž˜๋ชป๋˜์—ˆ๋‹ค๊ณ  ๋งํ•˜๋Š” ๊ฒƒ์€ ์‹ค์ˆ˜๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ ๋ชจ๋‹ฌ์€ ํŠธ๋ฆฌ๊ฑฐ์˜ ์ž์‹์ด ์•„๋‹ˆ๋ฏ€๋กœ ๋งˆ์น˜ ์žˆ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ Œ๋”๋ง๋˜์–ด์„œ๋Š” ์•ˆ ๋ฉ๋‹ˆ๋‹ค. ํ•œ ๊ฐ€์ง€ ๊ฐ€๋Šฅํ•œ ํ•ด๊ฒฐ์ฑ…์€ renderSubtreeIntoContainer ๋ฅผ ๊ณ„์† ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋˜ ๋‹ค๋ฅธ ์‚ฌ์šฉ์ž ์˜์—ญ ์˜ต์…˜์€ ๋ Œ๋”๋ง ๋ชจ๋‹ฌ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ์•ฑ ๋ฃจํŠธ ๊ทผ์ฒ˜์— ModalProvider ๋ฅผ ๋‘๊ณ  (์ปจํ…์ŠคํŠธ๋ฅผ ํ†ตํ•ด) ๋ฃจํŠธ์— ์ž„์˜์˜ ๋ชจ๋‹ฌ ์š”์†Œ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

renderSubtreeIntoContainer ๋Š” render ๋‚ด๋ถ€์—์„œ ํ˜ธ์ถœํ•  ์ˆ˜ ์—†๊ฑฐ๋‚˜ React 16์˜ ์ˆ˜๋ช… ์ฃผ๊ธฐ ๋ฉ”์„œ๋“œ์—์„œ ํ˜ธ์ถœํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋ฉด 16)์œผ๋กœ์˜ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜์—์„œ ์™„์ „ํžˆ ์ค‘๋‹จ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ํฌํ„ธ์€ ๊ณต์‹ ๊ถŒ์žฅ ์‚ฌํ•ญ์ž…๋‹ˆ๋‹ค. https://reactjs.org/blog/2017/09/26/react-v16.0.html#breaking -changes

Portal์˜ ๊ฐœ๋…์ด ๊ณผ๋ถ€ํ•˜ ์ƒํƒœ๊ฐ€ ๋˜์—ˆ์„ ์ˆ˜๋„ ์žˆ๋‹ค๋Š” ๋ฐ ๋™์˜ํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๊ธ€๋กœ๋ฒŒ ๊ตฌ์„ฑ ์š”์†Œ์˜ ์†”๋ฃจ์…˜๊ณผ ์ด์— ๋Œ€ํ•œ ์ปจํ…์ŠคํŠธ๊ฐ€ ๋งˆ์Œ์— ๋“ค์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค. ์ด๋ฒคํŠธ๊ฐ€ ๋ฒ„๋ธ”๋ง๋˜์–ด์•ผ ํ•˜๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ์ง€์ •ํ•˜๋Š” createPortal์˜ ํ”Œ๋ž˜๊ทธ๋กœ ์ด ๋ฌธ์ œ๋ฅผ ์‰ฝ๊ฒŒ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. 16์„ธ ์ด์ƒ๊ณผ์˜ API ํ˜ธํ™˜์„ฑ์„ ์œ ์ง€ํ•˜๋Š” ์˜ตํŠธ์ธ ํ”Œ๋ž˜๊ทธ๊ฐ€ ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

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

class RenderToLayer extends Component {
  ...
  stop = e => e.stopPropagation()

  render() {
    const { open, layerClassName, useLayerForClickAway, render: renderLayer } = this.props

    if (!open) { return null }

    return createPortal(
      <div
        ref={this.handleLayer}
        style={useLayerForClickAway ? clickAwayStyle : null}
        className={layerClassName}
        onClick={this.stop}
        onContextMenu={this.stop}
        onDoubleClick={this.stop}
        onDrag={this.stop}
        onDragEnd={this.stop}
        onDragEnter={this.stop}
        onDragExit={this.stop}
        onDragLeave={this.stop}
        onDragOver={this.stop}
        onDragStart={this.stop}
        onDrop={this.stop}
        onMouseDown={this.stop}
        onMouseEnter={this.stop}
        onMouseLeave={this.stop}
        onMouseMove={this.stop}
        onMouseOver={this.stop}
        onMouseOut={this.stop}
        onMouseUp={this.stop}

        onKeyDown={this.stop}
        onKeyPress={this.stop}
        onKeyUp={this.stop}

        onFocus={this.stop}
        onBlur={this.stop}

        onChange={this.stop}
        onInput={this.stop}
        onInvalid={this.stop}
        onSubmit={this.stop}
      >
        {renderLayer()}
      </div>, document.body)
  }
  ...
}

์ด ๊ตฌ์„ฑ ์š”์†Œ๋Š” React ๋ฌธ์„œ์˜ ๋ชจ๋“  ์ด๋ฒคํŠธ ์œ ํ˜•์— ๋Œ€ํ•œ ์ „ํŒŒ๋ฅผ ์ค‘์ง€ํ•˜๊ณ  React 16์œผ๋กœ ์—…๋ฐ์ดํŠธํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

ํฌํ„ธ์— ์—ฐ๊ฒฐํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ? ํฌํ„ธ์„ ์ƒŒ๋“œ๋ฐ•์‹ฑํ•˜๋Š” ๋Œ€์‹  <React.Sandbox>...</React.Sandbox> ์žˆ๋‹ค๋ฉด ์–ด๋–จ๊นŒ์š”?

๊ทธ๋งˆ์ €๋„ ๋‚˜์—๊ฒŒ๋Š” ๋ถˆํ•„์š”ํ•˜๊ฒŒ ๋ณต์žกํ•ด ๋ณด์ธ๋‹ค. ๋ฒ„๋ธ”๋ง ๋™์ž‘์„ ์ฐจ๋‹จํ•  ์ˆ˜ ์žˆ๋„๋ก createPortal์— ์„ ํƒ์  ๋ถ€์šธ ํ”Œ๋ž˜๊ทธ๋ฅผ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š๋Š” ์ด์œ ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

@gaearon ์ด๊ฒƒ์€ ์šฐ๋ฆฌ ์ค‘ ์ผ๋ถ€์—๊ฒŒ ๋งค์šฐ ๋ถˆํ–‰ํ•œ ์ƒํ™ฉ์ž…๋‹ˆ๋‹ค. ๊ท€ํ•˜ ๋˜๋Š” ๊ท€ํ•˜์˜ ์†Œ์ค‘ํ•œ ์‚ฌ๋žŒ์ด ์ด๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? :)

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

์ด๋ฒคํŠธ ์ „ํŒŒ๊ฐ€ ์•„๋ฌด ๊ฒƒ๋„ ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š์„ ๋งŒํผ ์ถฉ๋ถ„ํžˆ ๋†’์€ createPortal ๋ฅผ ํ†ตํ•ด ๋ Œ๋”๋งํ•˜๋Š” ์•ฑ ๋ฃจํŠธ์— ๋” ๊ฐ€๊นŒ์šด ModalProvider๋กœ ์œ ์Šค์ผ€์ด์Šค๋ฅผ _ํ•  ์ˆ˜ ์žˆ๋Š”_ ๋Œ€๋ถ€๋ถ„ ํ•ด๊ฒฐ๋  ์ˆ˜ ์žˆ์ง€๋งŒ ์ด๋Š” ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์ฒ˜๋Ÿผ ๋Š๊ปด์ง€๊ธฐ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค. ์ž˜ ์„ค๊ณ„๋œ ๊ฑด์ถ•๋ฌผ. ๋˜ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—์„œ ์ œ๊ณตํ•˜๋Š” ๋ชจ๋‹ฌ์ด ๋” ์ด์ƒ ์ž์ฒด ํฌํ•จ๋˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์‚ฌ์šฉ์ž๋ฅผ ๋” ์„ฑ๊ฐ€์‹œ๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

๋‚˜๋Š” createPortal ๊ฐ€ ๋‘ ๊ฐ€์ง€ ๋ชจ๋‘๋ฅผ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š๋Š” API ์ธก๋ฉด์—์„œ ์ถ”๊ฐ€ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ชจ๋‹ฌ ์ผ€์ด์Šค๋Š” ๊ณ ์œ ํ•œ ๋‚˜๋ฌด์— ๊ฝค ๊ฐ€๊น๊ธฐ ๋•Œ๋ฌธ์— ReactDOM.render (old skool)์„ ์‚ฌ์šฉํ•˜๊ธฐ๋ฅผ ์ •๋ง๋กœ ์›ํ•ฉ๋‹ˆ๋‹ค _except_ ์ปจํ…์ŠคํŠธ ์ „ํŒŒ๊ฐ€ ์ข…์ข… ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

@kib357์ด ๊ฒŒ์‹œํ•œ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•œ ๊ฒฐ๊ณผ ์™ธ๋ถ€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ํฌ์ปค์Šค ๊ด€๋ฆฌ ์ฝ”๋“œ์—์„œ ์ง„๋‹จํ•˜๊ธฐ ๋งค์šฐ ์–ด๋ ค์šด ๋ฒ„๊ทธ๋ฅผ ์ˆ˜์ •

ํŠนํžˆ : ํ•ฉ์„ฑ ์ดˆ์  ์ด๋ฒคํŠธ ์ธ stopPropagation๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ๋„ ์˜๋ฏธ #document์— ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์บก์ฒ˜์˜๋ฅผ, ๋ฐ˜์ž‘์šฉ์˜ ๊ธฐ๋ณธ ํฌ์ปค์Šค ์ด๋ฒคํŠธ์—์„œ ํ˜ธ์ถœ์— ํฌํ„ธ ์›์ธ ์ธ stopPropagation ๋ฐ–์œผ๋กœ ๋ฒ„๋ธ” ๋ง์—์„œ ๊ทธ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด์ด ๋‹ค๋ฅธ ์บก์ฒ˜ ํ•ธ๋“ค๋Ÿฌ๋ฅผํ•˜์ง€ ์•Š์•˜๋‹ค <body> . ์šฐ๋ฆฌ๋Š” ํ•ธ๋“ค๋Ÿฌ๋ฅผ #document๋กœ ์ด๋™ํ•˜์—ฌ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ–ˆ์ง€๋งŒ React์˜ ๋ฐœ๊ฐ€๋ฝ์„ ๋ฐŸ์ง€ ์•Š๊ธฐ ์œ„ํ•ด ๊ณผ๊ฑฐ์—๋Š” ํŠนํžˆ ๊ทธ๋ ‡๊ฒŒ ํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

Portal์˜ ์ƒˆ๋กœ์šด ๋ฒ„๋ธ”๋ง ๋™์ž‘์€ ์ •๋ง ์†Œ์ˆ˜์˜ ๊ฒฝ์šฐ์ฒ˜๋Ÿผ ๋Š๊ปด์ง‘๋‹ˆ๋‹ค. ๊ทธ ์˜๊ฒฌ์ด๋‚˜ ์ง„์‹ค์ด ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ฌธ์ œ์— ๋Œ€ํ•ด ๊ด€์‹ฌ์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? @gaearon? ์ƒํ›„ 4๊ฐœ์›”์ธ๋ฐ ์ •๋ง ๊ณ ํ†ต์Šค๋Ÿฝ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ์ด๊ฒƒ์ด ์™„์ „ํžˆ ์•ˆ์ „ํ•œ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์ด ์—†๋Š” React 16์˜ ์ฃผ์š” API ๋ณ€๊ฒฝ์ด๋ผ๋Š” ์ ์„ ๊ฐ์•ˆํ•  ๋•Œ ์ด๊ฒƒ์ด ๋ฒ„๊ทธ๋กœ ๊ณต์ •ํ•˜๊ฒŒ ์„ค๋ช…๋  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

@craigkovatch ๋‚ด ์ธ๋ผ์ธ ์˜ˆ์ œ๋ฅผ ์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ• ์ง€ ์—ฌ์ „ํžˆ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค. ํŒ์—…์ด ์ƒ์ž์˜ ํฌ๊ธฐ๋ฅผ ๋‚ฎ์ถ”๊ณ  ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ํฌ๊ธฐ๊ฐ€ ์ฃผ์–ด์ง„ ๋ ˆ์ด์•„์›ƒ์—์„œ ๋ฌด์–ธ๊ฐ€๋ฅผ ์•„๋ž˜๋กœ ๋ฐ€์–ด๋‚ด๊ธฐ ๋•Œ๋ฌธ์— ๋ฌด์–ธ๊ฐ€๋ฅผ ์ธ๋ผ์ธํ•˜๋Š” ๊ฒƒ์€ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ƒฅ ๋„˜์–ด๊ฐˆ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

์ž ์žฌ์ ์œผ๋กœ ํŒ์˜ค๋ฒ„๋ฅผ ์ธก์ •ํ•˜๊ณ  ๋™์ผํ•œ ํฌ๊ธฐ์˜ ๋นˆ ์ž๋ฆฌ ํ‘œ์‹œ์ž๋ฅผ ์‚ฝ์ž…ํ•˜๊ณ  ์ƒ๋‹จ์— ์ •๋ ฌํ•˜๋ ค๊ณ  ์‹œ๋„ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์‚ฌ๋žŒ๋“ค์ด ํ•˜๋Š” ์ผ์€ ์•„๋‹™๋‹ˆ๋‹ค.

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

์ผ๋ฐ˜์ ์œผ๋กœ ์ด๊ฒƒ์ด ๋‘ ์‹œ๋‚˜๋ฆฌ์˜ค ๋ชจ๋‘์—์„œ ์ž‘๋™ํ•˜๋Š” ํŒจํ„ด์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

class Foo extends React.Component {
  state = {
    highlight: false,
    showFlyout: false,
  };

  mouseEnter() {
    this.setState({ highlight: true });
  }

  mouseLeave() {
    this.setState({ highlight: false });
  }

  showFlyout() {
    this.setState({ showFlyout: true });
  }

  hideFlyout() {
    this.setState({ showFlyout: false });
  }

  render() {
    return <>
      <div onMouseEnter={this.mouseEnter} onMouseLeave={this.mouseLeave} className={this.state.highlight ? 'highlight' : null}>
        Hello
        <Button onClick={this.showFlyout} />
      </div>
      {this.state.showFlyout ? <Flyout onHide={this.hideFlyout} /> : null}
    </>;
  }
}

ํ”Œ๋ผ์ด์•„์›ƒ์ด ํฌํ„ธ์ธ ๊ฒฝ์šฐ ์ž‘๋™ํ•˜๋ฉฐ ํฌํ„ธ ์œ„๋กœ ๋งˆ์šฐ์Šค๋ฅผ ๊ฐ€์ ธ๊ฐ€๋ฉด ์ด๋ฒคํŠธ ์œ„๋กœ ๋งˆ์šฐ์Šค๊ฐ€ ์ด๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋” ์ค‘์š”ํ•œ ๊ฒƒ์€ ํฌํ„ธ์ด ์•„๋‹ˆ๊ณ  ์ธ๋ผ์ธ ํ”Œ๋ผ์ด์•„์›ƒ์ด์–ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ์—๋„ ์ž‘๋™ํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. stopPropagation์ด ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์‚ฌ์šฉ ์‚ฌ๋ก€์—์„œ ์ž‘๋™ํ•˜์ง€ ์•Š๋Š” ์ด ํŒจํ„ด์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

@sebmarkbage ์šฐ๋ฆฌ๋Š” ์™„์ „ํžˆ ๋‹ค๋ฅธ ๋ฐฉ์‹์œผ๋กœ Portal์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. <body> ์˜ ์ตœ์ข… ์ž์‹์œผ๋กœ ๋งˆ์šดํŠธ๋œ ์ปจํ…Œ์ด๋„ˆ๋กœ ๋ Œ๋”๋งํ•œ ๋‹ค์Œ ์œ„์น˜ ์ง€์ •(๋•Œ๋กœ๋Š” z-์ƒ‰์ธ ํฌํ•จ)ํ•ฉ๋‹ˆ๋‹ค. React ๋ฌธ์„œ๋Š” ์ด๊ฒƒ์ด ๋””์ž์ธ ์˜๋„์— ๋” ๊ฐ€๊น๋‹ค๊ณ  ์ œ์•ˆํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰, DOM์—์„œ ์™„์ „ํžˆ ๋‹ค๋ฅธ ์œ„์น˜๋กœ ๋ Œ๋”๋งํ•ฉ๋‹ˆ๋‹ค. ์šฐ๋ฆฌ์˜ ์‚ฌ์šฉ ์‚ฌ๋ก€๊ฐ€ ์ด ์Šค๋ ˆ๋“œ์— ์†ํ•  ๋งŒํผ ์ถฉ๋ถ„ํžˆ ์œ ์‚ฌํ•˜์ง€ ์•Š์€ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ํ•จ๊ป˜ ๋ธŒ๋ ˆ์ธ์Šคํ† ๋ฐ/๋ฌธ์ œ ํ•ด๊ฒฐ์„ ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ๋‹ค๋ฅธ ํฌ๋Ÿผ์—์„œ ๋” ์ž์„ธํžˆ ๋…ผ์˜ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

์•„๋‹ˆ์š” ๋‚ด ์‚ฌ์šฉ ์‚ฌ๋ก€๋Š” ๋‘˜ ๋‹ค ์ž…๋‹ˆ๋‹ค. ๋•Œ๋กœ๋Š” ํ•˜๋‚˜, ๋•Œ๋กœ๋Š” ๋‹ค๋ฅธ ํ•˜๋‚˜. ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ๊ด€๋ จ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

<Flyout /> ๋Š” body์˜ ์ตœ์ข… ์ž์‹์œผ๋กœ ๋ Œ๋”๋งํ• ์ง€ ์—ฌ๋ถ€๋ฅผ ์„ ํƒํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ํฌํ„ธ ์ž์ฒด๋ฅผ ์ž์‹์ด ์•„๋‹Œ ํ˜ธ๋ฒ„๋ง๋œ ๊ตฌ์„ฑ ์š”์†Œ์˜ ํ˜•์ œ๋กœ ๋Œ์–ด์˜ฌ๋ฆฌ๊ธฐ๋งŒ ํ•˜๋ฉด ์‹œ๋‚˜๋ฆฌ์˜ค๊ฐ€ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

๋‚˜๋Š” ๊ทธ๊ฒƒ์ด ๋ถˆํŽธํ•˜๊ณ  ๊นŠ์ด ์ค‘์ฒฉ๋œ ๊ตฌ์„ฑ ์š”์†Œ์—์„œ ์‚ฌ๋ฌผ์„ ์ˆœ๊ฐ„ ์ด๋™ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์›ํ•˜๋Š” ๊ทธ๋Ÿด๋“ฏํ•œ ์‹œ๋‚˜๋ฆฌ์˜ค๊ฐ€ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€๋งŒ ๊ทธ ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ๋Š” ์ปจํ…์ŠคํŠธ๊ฐ€ ์ค‘๊ฐ„ ์ง€์ ์˜ ์ปจํ…์ŠคํŠธ์ธ ๊ฒƒ์ด ๊ดœ์ฐฎ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋‚˜๋Š” ๊ทธ๊ฒƒ๋“ค์„ ๋ณ„๊ฐœ์˜ ๋‘ ๊ฐ€์ง€ ๋ฌธ์ œ๋กœ ์ƒ๊ฐํ•œ๋‹ค.

์ด๋ฅผ ์œ„ํ•ด ์Šฌ๋กฏ API๊ฐ€ ํ•„์š”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

class Foo extends React.Component {
  state = {
    showFlyout: false,
  };

  showFlyout() {
    this.setState({ showFlyout: true });
  }

  hideFlyout() {
    this.setState({ showFlyout: false });
  }

  render() {
    return <>
      Hello
      <Button onClick={this.showFlyout} />
      <SlotContent name="flyout">
        {this.state.showFlyout ? <Flyout onHide={this.hideFlyout} /> : null}
      </SlotContent>
    </>;
  }
}

class Bar extends React.Component {
  state = {
    highlight: false,
  };

  mouseEnter() {
    this.setState({ highlight: true });
  }

  mouseLeave() {
    this.setState({ highlight: false });
  }

  render() {
    return <>
      <div onMouseEnter={this.mouseEnter} onMouseLeave={this.mouseLeave} className={this.state.highlight ? 'highlight' : null}>
        <SomeContext>
          <DeepComponent />
        </SomeContext>
      </div>
      <Slot name="flyout" />
    </>;
  }
}

๊ทธ๋Ÿฌ๋ฉด ํฌํ„ธ์€ DeepComponent๊ฐ€ ์•„๋‹Œ Bar์˜ ์ปจํ…์ŠคํŠธ๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค. ์ปจํ…์ŠคํŠธ ๋ฐ ์ด๋ฒคํŠธ ๋ฒ„๋ธ”๋ง์€ ์—ฌ์ „ํžˆ โ€‹โ€‹๋™์ผํ•œ ํŠธ๋ฆฌ ๊ฒฝ๋กœ๋ฅผ ๊ณต์œ ํ•ฉ๋‹ˆ๋‹ค.

@sebmarkbage ๋ชจ๋‹ฌ ์ผ€์ด์Šค๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ๋ Œ๋”๋ง๋˜๋Š” ์‹œ์ ์˜ ์ปจํ…์ŠคํŠธ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ๋‚ด ์ƒ๊ฐ์— ๊ทธ๊ฒƒ์€ ์•ฝ๊ฐ„ ๋…ํŠนํ•œ ๊ฒฝ์šฐ์ž…๋‹ˆ๋‹ค. ๊ตฌ์„ฑ ์š”์†Œ๋Š” ๊ทธ๊ฒƒ์„ ๋ Œ๋”๋งํ•œ ๊ฒƒ์˜ ๋…ผ๋ฆฌ์  ์ž์‹์ด์ง€๋งŒ ๊ตฌ์กฐ์  ๊ตฌ์„ฑ ์š”์†Œ๋Š” _์•„๋‹™๋‹ˆ๋‹ค(๋” ๋‚˜์€ ๋‹จ์–ด๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์—). ์˜ˆ๋ฅผ ๋“ค์–ด ์ผ๋ฐ˜์ ์œผ๋กœ ์–‘์‹ ์ปจํ…์ŠคํŠธ(๋ฆด๋ ˆ์ด, formik, redux ์–‘์‹)์™€ ๊ฐ™์€ ๊ฒƒ์„ ์›ํ•ฉ๋‹ˆ๋‹ค. , ๋ฌด์—‡์ด๋“ ) ๊ทธ๋Ÿฌ๋‚˜ ํ†ต๊ณผํ•  DOM ์ด๋ฒคํŠธ๋Š” ์•„๋‹™๋‹ˆ๋‹ค. ๋˜ํ•œ ๊ทธ๋Ÿฌํ•œ ๋ชจ๋‹ฌ์€ ํŠธ๋ฆฌ๊ฑฐ ์˜†์— ์žˆ๋Š” ๋‚˜๋ฌด ๊นŠ์ˆ™ํ•œ ๊ณณ์— ๋ Œ๋”๋ง๋˜์–ด ๊ตฌ์กฐ์ ์œผ๋กœ ๊ฑฐ๊ธฐ์— ์†ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ตฌ์„ฑ ์š”์†Œ์™€ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅ ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.

์ด ๊ฒฝ์šฐ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ createPortal์ด ์ œ๊ณตํ•˜๋Š” ํ”Œ๋ผ์ด์•„์›ƒ/๋“œ๋กญ๋‹ค์šด ์ผ€์ด์Šค์™€ ๋‹ค๋ฅด๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. Tbc ํฌํ„ธ์˜ ๋ฒ„๋ธ”๋ง ๋™์ž‘์€ ์ข‹์ง€๋งŒ ๋ชจ๋‹ฌ์—๋Š” ์ ํ•ฉํ•˜์ง€ ์•Š๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋˜ํ•œ ์ด๊ฒƒ์ด Context ๋ฐ ์ผ์ข…์˜ ModalProvider๋กœ ํ•ฉ๋ฆฌ์ ์œผ๋กœ ์ž˜ ์ฒ˜๋ฆฌ๋  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€๋งŒ ํŠนํžˆ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ๊ฒฝ์šฐ ๋‹ค์†Œ ์„ฑ๊ฐ€์‹  ์ผ์ž…๋‹ˆ๋‹ค.

ํฌํ„ธ ์ž์ฒด๋ฅผ ์ž์‹์ด ์•„๋‹Œ ํ˜ธ๋ฒ„๋ง๋œ ๊ตฌ์„ฑ ์š”์†Œ์˜ ํ˜•์ œ๋กœ ๋Œ์–ด์˜ฌ๋ฆฌ๊ธฐ๋งŒ ํ•˜๋ฉด ์‹œ๋‚˜๋ฆฌ์˜ค๊ฐ€ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

๋‚ด๊ฐ€ ํŒ”๋กœ์šฐํ•˜๊ณ  ์žˆ๋Š”์ง€ ํ™•์‹คํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์˜ˆ๊ธฐ์น˜ ์•Š์€ DOM ํŠธ๋ฆฌ๋ฅผ ํ†ตํ•ด ๋ฒ„๋ธ”๋ง๋˜๋Š” keyDown ์ด๋ฒคํŠธ์™€ ๊ฐ™์€ ๋ฌธ์ œ๊ฐ€ ์—ฌ์ „ํžˆ ์žˆ์Šต๋‹ˆ๋‹ค.

@jquense ๋‚ด ์˜ˆ์—์„œ ์Šฌ๋กฏ์€ ์—ฌ์ „ํžˆ โ€‹โ€‹Bar ๊ตฌ์„ฑ ์š”์†Œ ๋‚ด์— ์žˆ์œผ๋ฏ€๋กœ <Form><Bar /></Form> ์™€ ๊ฐ™์€ ํ˜•์‹์˜ ์ปจํ…์ŠคํŠธ๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

ํฌํ„ธ์ด ๋ฌธ์„œ ๋ณธ๋ฌธ์œผ๋กœ ๋ Œ๋”๋ง๋˜๋”๋ผ๋„.

๋”ฐ๋ผ์„œ ๋‘ ๊ฐœ์˜ ๊ฐ„์ ‘ ์ฐธ์กฐ(ํฌํ„ธ๋ง)์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค. deep -> Bar์˜ ํ˜•์ œ -> ๋ฌธ์„œ ๋ณธ๋ฌธ์ž…๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ํฌํ„ธ์˜ ์ปจํ…์ŠคํŠธ๋Š” ์—ฌ์ „ํžˆ ์–‘์‹์˜ ์ปจํ…์ŠคํŠธ์ด๊ณ  ์ด๋ฒคํŠธ ๋ฒ„๋ธ”๋ง ์ฒด์ธ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€์ด์ง€๋งŒ ๋‘˜ ๋‹ค ํ˜ธ๋ฒ„๋ง๋œ ๊ฒƒ์˜ ์ปจํ…์ŠคํŠธ์— ์—†์Šต๋‹ˆ๋‹ค.

๋„ค ์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค ๋†“์ณค์–ด์š” ๐Ÿ˜ณ ์ œ๊ฐ€ ์ œ๋Œ€๋กœ ์ฝ๊ณ  ์žˆ๋‹ค๋ฉด ๊ทธ๋ž˜๋„ <Slot> ์—์„œ ๋ฒ„๋ธ”๋ง์ด ๋‚จ์•„์žˆ๊ฒ ์ฃ ? Modal ๋Œ€ํ™” ์ƒ์ž์˜ ๊ฒฝ์šฐ ์•„๋งˆ๋„ _any_ ๋ฒ„๋ธ”๋ง์„ ์›ํ•˜์ง€ ์•Š์„ ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜์ง€๋งŒ ๊ทธ๊ฒƒ์€ ํ™•์‹คํžˆ ๋” ์ข‹์Šต๋‹ˆ๋‹ค. ์Šคํฌ๋ฆฐ ๋ฆฌ๋”์˜ ๊ด€์ ์—์„œ ์ƒ๊ฐํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ชจ๋‹ฌ ์™ธ๋ถ€์˜ ๋ชจ๋“  ํ•ญ๋ชฉ์ด ์ผœ์ ธ ์žˆ๋Š” ๋™์•ˆ ๋ฐ˜์ „๋˜๊ธฐ๋ฅผ ์›ํ•ฉ๋‹ˆ๋‹ค. ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค. ๊ทธ ๊ฒฝ์šฐ ๋ฒ„๋ธ”๋ง์ด ๋ฌธ์ œ๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์•„๋ฌด๋„ ๋Œ€ํ™” ์ƒ์ž ๋‚ด๋ถ€์˜ ํด๋ฆญ์ด ์•„๋ฌด๋ฐ๋„ ๋ฒ„๋ธ”๋ง๋˜์ง€ ์•Š์„ ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์˜ ๋ฌธ์ œ๋Š” ํฌํ„ธ์ด ์•„๋‹ˆ์ง€๋งŒ ํŠธ๋ฆฌ ๊ฐ„์— ์ปจํ…์ŠคํŠธ๋ฅผ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ๋Š” ์ข‹์€ ๋ฐฉ๋ฒ•์ด ์—†์Šต๋‹ˆ๊นŒ? ์ปจํ…์ŠคํŠธ์˜ ์ผ๋ถ€์ธ ReactDOM.render ๋Š” ๋ชจ๋‹ฌ์— ๋Œ€ํ•ด ์ •๋ง ๊ดœ์ฐฎ๊ณ  ์–ด์จŒ๋“  ๊ทธ๊ฒƒ์— ๋Œ€ํ•ด ๋” "์˜ฌ๋ฐ”๋ฅธ" ์‚ฌ๊ณ  ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค...

์—ฌ๊ธฐ์—์„œ ๋‚ด ์ƒ๊ฐ์€ ์—ฌ์ „ํžˆ โ€‹โ€‹๋ชจ๋‹ฌ์—์„œ div, ๋ณธ๋ฌธ, ๋ฌธ์„œ, ์ฐฝ์œผ๋กœ ์ด๋™ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์•ฝ๊ฐ„์˜ ๋ฒ„๋ธ”๋ง์ด ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ฐœ๋…์ ์œผ๋กœ ํ”„๋ ˆ์ž„์„ ๋„˜์–ด ํฌํ•จํ•˜๋Š” ์ฐฝ ๋“ฑ์œผ๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.

์ด๋Š” ART ๋˜๋Š” GL ๋ Œ๋”๋ง ์ฝ˜ํ…์ธ (๋ฐ ์–ด๋Š ์ •๋„๋Š” React Native)์™€ ๊ฐ™์€ ์˜๋ฏธ ์ฒด๊ณ„๋ฅผ ๊ฐ€์ ธ์˜ฌ ๊ธฐ์กด ์ง€์› ํŠธ๋ฆฌ๊ฐ€ ์—†์„ ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ ์ด๋ก ์ ์ธ ๊ฒƒ์ด ์•„๋‹™๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ด๊ฒƒ์ด ๊ฑฐํ’ˆ ์ด ๋‚˜๋Š” ๊ณณ์ด๋ผ๊ณ  ๋งํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

์ผ๋ถ€ ์•ฑ์—๋Š” ๋ชจ๋‹ฌ์— ๋ชจ๋‹ฌ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด FB์—๋Š” ๋ชจ๋‹ฌ ์œ„์— ์žˆ์„ ์ˆ˜ ์žˆ๋Š” ์ฑ„ํŒ… ์ฐฝ์ด ์žˆ๊ฑฐ๋‚˜ ๋ชจ๋‹ฌ์ด ์ฑ„ํŒ… ์ฐฝ์˜ ์ผ๋ถ€์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋ชจ๋‹ฌ์กฐ์ฐจ๋„ ํŠธ๋ฆฌ์˜ ์–ด๋””์— ์†ํ•˜๋Š”์ง€์— ๋Œ€ํ•œ ์ปจํ…์ŠคํŠธ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์€ ๊ฒฐ์ฝ” ์™„์ „ํžˆ ๋…๋ฆฝ์ ์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ด๋ฒคํŠธ ๋ฒ„๋ธ”๋ง๊ณผ ์ปจํ…์ŠคํŠธ์— ๋Œ€ํ•ด ๋‘ ๊ฐ€์ง€ ๋‹ค๋ฅธ ์˜๋ฏธ๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์—†๋‹ค๋Š” ๋ง์€ ์•„๋‹™๋‹ˆ๋‹ค. ์ด๋Š” ์ด์— ๋Œ€ํ•ด ๋ช…์‹œ์ ์ด๋ฉฐ ๋‹ค๋ฅธ ํ•˜๋‚˜ ์—†์ด ํฌํ„ธ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‘˜ ๋‹ค ๋™์ผํ•œ ๊ฒฝ๋กœ๋ฅผ ๋”ฐ๋ฅด๋„๋ก ๋ณด์žฅํ•˜๋Š” ๊ฒƒ์€ ๋ธŒ๋ผ์šฐ์ €์—์„œ์™€ ๋™์ผํ•œ ์‚ฌ์šฉ์ž ๊ณต๊ฐ„ ์ด๋ฒคํŠธ์— ๋Œ€ํ•ด ์ด๋ฒคํŠธ ๋ฒ„๋ธ”๋ง์ด ์™„์ „ํžˆ ๊ตฌํ˜„๋  ์ˆ˜ ์žˆ์Œ์„ ์˜๋ฏธํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ •๋ง ๊ฐ•๋ ฅํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ์ด๊ฒƒ์€ ์˜ค๋Š˜๋‚  ๋‹ค์–‘ํ•œ Redux ์ปจํ…์ŠคํŠธ์—์„œ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. this.context.dispatch("Hover") ๊ฐ€ ์‚ฌ์šฉ์ž ๊ณต๊ฐ„ ์ด๋ฒคํŠธ ๋ฒ„๋ธ”๋ง์ด๋ผ๊ณ  ์ƒ์ƒํ•ด๋ณด์‹ญ์‹œ์˜ค. ์ปจํ…์ŠคํŠธ์˜ ์ผ๋ถ€๋กœ React ์ด๋ฒคํŠธ๋ฅผ ๊ตฌํ˜„ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ์ด๊ฒƒ์„ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋Š” ๊ฒƒ์ด ํ•ฉ๋ฆฌ์ ์ž…๋‹ˆ๋‹ค. ์ง€๊ธˆ ๋ชจ๋“  ๋ฉด์—์„œ ๋‹น์‹ ๋„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๋‘ ์ปจํ…์ŠคํŠธ๋ฅผ ๋ถ„๊ธฐํ•˜๋ฉด ์ผ๋ฐ˜ ์ปจํ…์ŠคํŠธ์™€ ๋ณ‘๋ ฌ๋กœ DOM ๊ตฌ์กฐ๋ฅผ ๋”ฐ๋ฅด๋Š” ๋‹ค๋ฅธ ์‚ฌ์šฉ์ž ๊ณต๊ฐ„ ์ปจํ…์ŠคํŠธ API๊ฐ€ ์ƒ์„ฑ๋  ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ ์Šฌ๋กฏ์ด ์ถฉ๋ถ„ํ•œ์ง€ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด ์•ฝ๊ฐ„ ๋ฐ˜๋Œ€ํ•˜๋Š” ์ด์œ ์ž…๋‹ˆ๋‹ค. ์™œ๋ƒํ•˜๋ฉด) ์–ด์จŒ๋“  ์–ด๋–ค ์ปจํ…์ŠคํŠธ ๋ฒ„๋ธ”๋ง์ด ๋ฐœ์ƒํ•˜๋Š”์ง€ ๋ช…์‹œํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. b) ์„ธ๊ณ„๋ฅผ ํฌํฌํ•˜๊ณ  ๋‘ ๊ฐœ์˜ ์ „์ฒด ์ปจํ…์ŠคํŠธ ์‹œ์Šคํ…œ์„ ๊ฐ–๋Š” ๊ฒƒ์„ ํ”ผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํŠนํžˆ: ํ•ฉ์„ฑ ํฌ์ปค์Šค ์ด๋ฒคํŠธ์—์„œ stopPropagation์„ ํ˜ธ์ถœํ•˜์—ฌ ํฌํ„ธ ๋ฐ–์œผ๋กœ ๋ฒ„๋ธ”๋ง๋˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜๋ฉด stopPropagation์ด #document์— ์žˆ๋Š” React์˜ ์บก์ฒ˜๋œ ํ•ธ๋“ค๋Ÿฌ์— ์žˆ๋Š” ๋„ค์ดํ‹ฐ๋ธŒ ํฌ์ปค์Šค ์ด๋ฒคํŠธ์—์„œ๋„ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.

. ์šฐ๋ฆฌ๋Š” ํ•ธ๋“ค๋Ÿฌ๋ฅผ #document๋กœ ์ด๋™ํ•˜์—ฌ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ–ˆ์ง€๋งŒ React์˜ ๋ฐœ๊ฐ€๋ฝ์„ ๋ฐŸ์ง€ ์•Š๊ธฐ ์œ„ํ•ด ๊ณผ๊ฑฐ์—๋Š” ํŠนํžˆ ๊ทธ๋ ‡๊ฒŒ ํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

@craigkovatch , ๋ฌธ์„œ์— onFocusCapture ์ด๋ฒคํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์…จ์Šต๋‹ˆ๊นŒ? ๋‚ด ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์—์„œ ์บก์ฒ˜๋œ ์ด๋ฒคํŠธ๋ฅผ ์ค‘์ง€ํ•˜๋ฉด ์•ˆ ๋ฉ๋‹ˆ๋‹ค. ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ์–ด๋–ค ์กฐ์น˜๋ฅผ ์ทจํ–ˆ๋Š”์ง€์— ๋Œ€ํ•œ ์ž์„ธํ•œ ์˜ˆ๋ฅผ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?
๋˜ํ•œ ๋‚ด ์ฝ”๋“œ์— blur ์ด๋ฒคํŠธ๋ฅผ ์ค‘์ง€ํ•˜๋Š” ๋ฐ ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์ค‘์ง€ํ•ด์„œ๋Š” ์•ˆ ๋ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ด ์งˆ๋ฌธ์„ ๋” ๊นŠ์ด ์กฐ์‚ฌํ•˜๊ณ  ๋ณด๋‹ค ์•ˆ์ •์ ์ธ ์†”๋ฃจ์…˜์„ ์ฐพ๊ธฐ ์œ„ํ•ด ๋…ธ๋ ฅํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@kib357 ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์— ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค๊ณ  ์ œ์•ˆํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ React์— ๋ณ„๋„์˜ ๋ฒ„๊ทธ๊ฐ€ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๋ฌธ์ œ์˜ ์ฝ”๋“œ๋Š” ๊ธฐ๋ณธ ์บก์ฒ˜ ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค(์˜ˆ: document.body.addEventListener('focus', handler, true)

์บก์ฒ˜๋œ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค๋Š” ์‚ฌ์‹ค์„ ๊ฐ์•ˆํ•  ๋•Œ @craigkovatch๋Š” ํฅ๋ฏธ๋กญ๊ฒŒ ๋“ค๋ฆฝ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์™œ ์ด๋Ÿฐ ์ผ์ด ๋ฐœ์ƒํ•˜๋Š”์ง€ ์•„๋ฌด ์ƒ๊ฐ์ด ์—†์Šต๋‹ˆ๋‹ค.

ํฌํ„ธ ๋ Œ๋”๋ง์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ๋‘ ๊ฐ€์ง€ ์‹œ๋‚˜๋ฆฌ์˜ค๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

  1. ๋“œ๋กญ๋‹ค์šด ๋ฒ„ํŠผ์ด๋‚˜ 1๋‹จ๊ณ„ ๋ฉ”๋‰ด์™€ ๊ฐ™์€ ๊ฐ„๋‹จํ•œ ์œ„์ ฏ์—์„œ overflow:hidden ๋“ฑ๊ณผ ๊ฐ™์€ CSS ๋ฌธ์ œ๋ฅผ ๋ฐฉ์ง€ํ•˜๋ ค๋ฉด
  2. ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ณด๋‹ค ๊ฐ•๋ ฅํ•œ ๊ฒฝ์šฐ๋ฅผ ์œ„ํ•ด ์ƒˆ๋กœ์šด UX ๋ ˆ์ด์–ด๋ฅผ ์ƒ์„ฑํ•˜๋ ค๋ฉด:
  3. ๋ชจ๋‹ฌ
  4. ์ค‘์ฒฉ ๋ฉ”๋‰ด
  5. popovers-with-forms-with-dropdowns-... โ€“ ๋ ˆ์ด์–ด๊ฐ€ ๊ฒฐํ•ฉ๋œ ๋ชจ๋“  ๊ฒฝ์šฐ

ํ˜„์žฌ createPortal API๋Š” ์ฒซ ๋ฒˆ์งธ ์‹œ๋‚˜๋ฆฌ์˜ค๋งŒ ์ถฉ์กฑํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋‘ ๋ฒˆ์งธ๋กœ ์ƒˆ๋กœ์šด React.render๋ฅผ ์‚ฌ์šฉํ•˜๋ผ๋Š” ์ œ์•ˆ์€ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋ชจ๋“  ๋ ˆ์ด์–ด์— ๋Œ€ํ•ด ๋ชจ๋“  ์ œ๊ณต์ž๊ฐ€ ์žˆ๋Š” ๋ณ„๋„์˜ ์•ฑ์„ ๋งŒ๋“œ๋Š” ๊ฒƒ์€ ๋งค์šฐ ์ข‹์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋˜๋Š” ์ถ”๊ฐ€ ์ •๋ณด๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?
createPortal API์—์„œ ์ œ์•ˆ๋œ ๋งค๊ฐœ๋ณ€์ˆ˜์˜ ๋‹จ์ ์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

@sebmarkbage ์Šฌ๋กฏ API์— ๋Œ€ํ•œ ์ฆ‰๊ฐ์ ์ธ ์งˆ๋ฌธ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ SlotContents ๋ฅผ ๋™์‹œ์— ํ•˜๋‚˜์˜ Slot ์— ์‚ฝ์ž…ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? ์ธํ„ฐํŽ˜์ด์Šค์—์„œ ์—ฌ๋Ÿฌ "ํŒ์—…" ๋˜๋Š” "๋ชจ๋‹ฌ"์„ ๋™์‹œ์— ์—ฌ๋Š” ๊ฒƒ์€ ๋“œ๋ฌธ ์ผ์ด ์•„๋‹™๋‹ˆ๋‹ค. ๋‚ด ์™„๋ฒฝํ•œ ์„ธ๊ณ„์—์„œ Popup API๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ณด์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

import { App } from './app'
import { PopupSlot } from './popups'

let root = (
  <div>
    <App />
    <PopupSlot />
  </div>
)

ReactDOM.render(root, document.querySelector('#root'))

// some dark corner of our app

import { Popup } from './popups'

export function SoManyPopups () {
  return <>
    <Popup>My Entire</Popup>
    <Popup>Interface</Popup>
    <Popup>Is Popups</Popup>
  </>
}

์ด์— ๋Œ€ํ•œ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์„ ์™„์ „ํžˆ ์ฐพ์„ ์ˆ˜ ์—†๋Š” ์ƒˆ๋กœ์šด ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์œ„์—์„œ ์ œ์•ˆํ•œ "์ด๋ฒคํŠธ ํŠธ๋žฉ" ์ ‘๊ทผ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๋ฉด React Synthetic ์ด๋ฒคํŠธ๋งŒ ํฌํ„ธ์—์„œ ๋ฒ„๋ธ”๋ง๋˜์ง€ ์•Š๋„๋ก ์ฐจ๋‹จ๋ฉ๋‹ˆ๋‹ค. ๊ธฐ๋ณธ ์ด๋ฒคํŠธ๋Š” ์—ฌ์ „ํžˆ ๊ฑฐํ’ˆ์ด ์ผ๊ณ  React ์ฝ”๋“œ๋Š” ๋Œ€๋ถ€๋ถ„ jQuery ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ ๋‚ด๋ถ€์—์„œ ํ˜ธ์ŠคํŒ…๋˜๋ฏ€๋กœ <body> ์˜ ์ „์—ญ jQuery keyDown ํ•ธ๋“ค๋Ÿฌ๋Š” ์—ฌ์ „ํžˆ ์ด๋ฒคํŠธ๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

์ด์™€ ๊ฐ™์€ ref๋ฅผ ํ†ตํ•ด Portal ๋‚ด๋ถ€์˜ ๊ธฐ๋ณธ ์ปจํ…Œ์ด๋„ˆ ์š”์†Œ์— event.stopPropagation ๋ฆฌ์Šค๋„ˆ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ ค๊ณ  ์‹œ๋„ํ–ˆ์ง€๋งŒ ์ด๋Š” ํฌํ„ธ ๋‚ด์˜ ๋ชจ๋“  Synthetic ์ด๋ฒคํŠธ๋ฅผ ์™„์ „ํžˆ ๋ฌดํšจํ™”ํ–ˆ์Šต๋‹ˆ๋‹ค. React์˜ ์ตœ์ƒ์œ„ ๋ฆฌ์Šค๋„ˆ๊ฐ€ ์บก์ฒ˜ ๋‹จ๊ณ„๋ฅผ ๋ณด๊ณ  ์žˆ๋‹ค๊ณ  ์ž˜๋ชป ๊ฐ€์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.

React์— ๋Œ€ํ•œ ๋ณ€๊ฒฝ ์‚ฌํ•ญ ์™ธ์— ์—ฌ๊ธฐ์„œ ๋ฌด์—‡์„ ํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ํ™•์‹คํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

const allTheEvents: string[] = 'click contextmenu doubleclick drag dragend dragenter dragexit dragleave dragover dragstart drop mousedown mouseenter mouseleave mousemove mouseover mouseout mouseup keydown keypress keyup focus blur change input invalid submit'.split(' ');
const stop = (e: React.SyntheticEvent<HTMLElement>): void => { e.stopPropagation(); };
const nativeStop = (e: Event): void => e.stopPropagation();
const handleRef = (ref: HTMLDivElement | null): void => {
  if (!ref) { return; }
  allTheEvents.forEach(eventName => ref.addEventListener(eventName, nativeStop));
};


/** Prevents https://reactjs.org/docs/portals.html#event-bubbling-through-portals */
export function PortalEventTrap(children: React.ReactNode): JSX.Element {
  return <div
      onClick={stop}
      ...

      ref={handleRef}
    >
      {children}
    </div>;
}

์ด๋Š” ReactDOM ๋ฐ JQuery๊ฐ€ ์ดˆ๊ธฐํ™”๋˜๋Š” ์ˆœ์„œ์— ๋”ฐ๋ผ ๋‹ค๋ฆ…๋‹ˆ๋‹ค. JQuery๊ฐ€ ๋จผ์ € ์ดˆ๊ธฐํ™”๋˜๋ฉด JQuery์˜ ์ตœ์ƒ์œ„ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ๋จผ์ € ์„ค์น˜๋˜๋ฏ€๋กœ ReactDOM์˜ ํ•ฉ์„ฑ ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ์‹คํ–‰๋˜๊ธฐ ์ „์— ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

ReactDOM๊ณผ JQuery๋Š” ๋ชจ๋‘ scroll ์™€ ๊ฐ™์ด ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๋ฒ„๋ธ”๋งํ•˜์ง€ ์•Š๋Š” ์ด๋ฒคํŠธ๊ฐ€ ์—†๋Š” ํ•œ ๋‚ด๋ถ€์ ์œผ๋กœ ๋ฒ„๋ธ”๋ง์„ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ํ•˜๋Š” ๋‹จ์ผ ์ตœ์ƒ์œ„ ๋ฆฌ์Šค๋„ˆ๋งŒ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ์„ ํ˜ธํ•ฉ๋‹ˆ๋‹ค.

@Kovensky ๋‚ด ์ดํ•ด๋Š” jQuery๊ฐ€ React ๋ฐฉ์‹์œผ๋กœ "ํ•ฉ์„ฑ ๋ฒ„๋ธ”๋ง"์„ ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š์•˜์œผ๋ฏ€๋กœ ๋‹จ์ผ ์ตœ์ƒ์œ„ ๋ฆฌ์Šค๋„ˆ๊ฐ€ ์—†๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋‚ด DOM ๊ด€๋ฆฌ์ž๋„ ํ•˜๋‚˜๋ฅผ ๊ณต๊ฐœํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ํ‹€๋ ธ๋‹ค๋ฉด ๋‹น์‹ ์ด ์ฐธ์กฐํ•˜๋Š” ๊ฒƒ์„๋ณด๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.

์œ„์ž„๋œ ์ด๋ฒคํŠธ์˜ ๊ฒฝ์šฐ์ž…๋‹ˆ๋‹ค. ์˜ˆ: $(document.body).on('click', '.my-selector', e => e.stopPropagation()) .

๋ณด์„ธ์š”. ๋ˆ„๊ตฐ๊ฐ€ ์ฝ”๋“œ๋ฅผ ์žฌ๊ตฌ์„ฑํ•ด์•ผ ํ•˜๋Š” ์œ„์—์„œ ์ œ์•ˆํ•œ ๋””์ž์ธ์œผ๋กœ๋Š” ํ•ด๊ฒฐํ•  ์ˆ˜ ์—†๋‹ค๊ณ  ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ๋‚˜์—๊ฒŒ ํ™•์‹ ์„ ์ค€๋‹ค๋ฉด ์ด๊ฒƒ์€ React์—์„œ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋น ๋ฅธ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์„ ์ฐพ๋Š” ๊ฒƒ ์™ธ์—๋Š” ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์—†๋Š” ์ด์œ ๋ฅผ ๋ณด์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค.

@sebmarkbage ๊ท€ํ•˜์˜ ์ œ์•ˆ์€ ์ด๋ฒคํŠธ๊ฐ€ ์ง๊ณ„ ์†Œ์œ ์ž์—๊ฒŒ ์ „ํŒŒ๋˜๋Š” ๊ฒฝ์šฐ์—๋งŒ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋จธ์ง€ ๋‚˜๋ฌด๋Š” ์–ด๋–ป์Šต๋‹ˆ๊นŒ?

๋‹ค์Œ์€ Slots ๋˜๋Š” createPortal๋กœ ์ž˜ ํ•ด๊ฒฐํ•  ์ˆ˜ ์—†๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋Š” ์‚ฌ์šฉ ์‚ฌ๋ก€์ž…๋‹ˆ๋‹ค.

<Form defaultValue={fromValue}>
   <more-fancy-markup />
   <div>
     <Field name="faz"/>
     <ComplexFieldModal>
       <Field name="foo.bar"/>
       <Field name="foo.baz"/>
     </ComplexFieldModal>
  </div>
</Form>

๊ทธ๋ฆฌ๊ณ  ์—ฌ๊ธฐ์—๋Š” ์œ ์‚ฌํ•˜์ง€๋งŒ ์•ฝ๊ฐ„ ๋‹ค๋ฅธ ์„ค์ •์ด ์žˆ๋Š” gif๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—์„œ ๋ฐ˜์‘ํ˜• ์‚ฌ์ดํŠธ์— ๋Œ€ํ•ด createPortal์„ ์‚ฌ์šฉํ•˜์—ฌ ์–‘์‹ ํ•„๋“œ๋ฅผ ์•ฑ ๋„๊ตฌ ๋ชจ์Œ(ํŠธ๋ฆฌ์˜ ํ›จ์”ฌ ๋” ๋†’์€ ์œ„์น˜)์œผ๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ์—๋„ ์ด๋ฒคํŠธ๊ฐ€ ํŽ˜์ด์ง€ ์ฝ˜ํ…์ธ ๋กœ ๋‹ค์‹œ ๋ฒ„๋ธ”๋ง๋˜๋Š” ๊ฒƒ์„ ์›ํ•˜์ง€ ์•Š์ง€๋งŒ Form ์ปจํ…์ŠคํŠธ๊ฐ€ ํ•จ๊ป˜ ๊ฐ€๊ธฐ๋ฅผ ์›ํ•ฉ๋‹ˆ๋‹ค. ๋‚ด ๊ตฌํ˜„ btw๋Š” ์ปจํ…์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์Šฌ๋กฏ๊ณผ ๊ฐ™์€ ๊ฒƒ์ž…๋‹ˆ๋‹ค ...

large gif 640x320

@sebmarkbage unstable_renderSubtreeIntoContainer ๋Š” ๊ณ„์ธต ๋‚ด์—์„œ ๋˜๋Š” ๋ณ„๋„์˜ ํŒจํ‚ค์ง€ ํ”„๋ ˆ์ž„์›Œํฌ์˜ ์ผ๋ถ€๋กœ ๊ตฌ์„ฑ ์š”์†Œ์˜ ์œ„์น˜์— ๊ด€๊ณ„์—†์ด ๊ณ„์ธต์˜ ๋งจ ์œ„์— ์ง์ ‘ ์•ก์„ธ์Šคํ•  ์ˆ˜ ์žˆ๋„๋ก ํ—ˆ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.

์ด์— ๋น„ํ•ด ์Šฌ๋กฏ ์†”๋ฃจ์…˜์—๋Š” ๋ช‡ ๊ฐ€์ง€ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์†”๋ฃจ์…˜์€ ๋ฒ„๋ธ” ์ด๋ฒคํŠธ์— ๋Œ€ํ•ด "OK"์ธ ๊ณ„์ธต์˜ ์œ„์น˜์— ๋Œ€ํ•œ ์•ก์„ธ์Šค ๊ถŒํ•œ์ด ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๊ตฌ์„ฑ ์š”์†Œ ๋ฐ ๊ตฌ์„ฑ ์š”์†Œ ํ”„๋ ˆ์ž„์›Œํฌ์˜ ๊ฒฝ์šฐ๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค.
  • ๊ณ„์ธต์˜ ๋‹ค๋ฅธ ์ˆ˜์ค€์—์„œ ์ด๋ฒคํŠธ๋ฅผ ๋ฒ„๋ธ”๋งํ•˜๋Š” ๊ฒƒ์ด "ํ™•์ธ"์ด๋ผ๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค.
  • ์ด๋ฒคํŠธ๋Š” ์—ฌ์ „ํžˆ ์Šฌ๋กฏ์˜ ์œ„์น˜์—์„œ ๋ฒ„๋ธ”๋ง๋ฉ๋‹ˆ๋‹ค. ( @craigkovatch๊ฐ€ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด)

๋˜ํ•œ ์œ ์Šค์ผ€์ด์Šค๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค(์ด๋ฏธ ์–ธ๊ธ‰ํ•œ ๊ฒƒ๊ณผ ์œ ์‚ฌํ•  ์ˆ˜ ์žˆ์Œ).

์‚ฌ์šฉ์ž๊ฐ€ "์˜ฌ๊ฐ€๋ฏธ"๋กœ ๋งˆ์šฐ์Šค๋กœ ๋ฌผ๊ฑด์„ ์„ ํƒํ•  ์ˆ˜ ์žˆ๋Š” ํ‘œ๋ฉด์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๊ธฐ๋ณธ์ ์œผ๋กœ 100% ๋„ˆ๋น„/๋†’์ด์ด๋ฉฐ ๋‚ด ์•ฑ์˜ ๋ฃจํŠธ์— ์žˆ์œผ๋ฉฐ onMouseDown ์ด๋ฒคํŠธ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ด ํ‘œ๋ฉด์—๋Š” ๋ชจ๋‹ฌ ๋ฐ ๋“œ๋กญ๋‹ค์šด๊ณผ ๊ฐ™์€ ํฌํ„ธ์„ ์—ฌ๋Š” ๋ฒ„ํŠผ๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ํฌํ„ธ ๋‚ด๋ถ€์˜ mouseDown ์ด๋ฒคํŠธ๋Š” ์‹ค์ œ๋กœ ์•ฑ ๋ฃจํŠธ์˜ ์˜ฌ๊ฐ€๋ฏธ ์„ ํƒ ๊ตฌ์„ฑ ์š”์†Œ์— ์˜ํ•ด ๊ฐ€๋กœ์ฑ„์–ด์ง‘๋‹ˆ๋‹ค.

๋‚˜๋Š” ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๋งŽ์€ ๊ฒƒ์„ ๋ณธ๋‹ค:

  • ํฌํ„ธ์„ ๋ฃจํŠธ ์˜ฌ๊ฐ€๋ฏธ ๊ตฌ์„ฑ ์š”์†Œ๋ณด๋‹ค ํ•œ ๋‹จ๊ณ„ ์œ„์— ๋ Œ๋”๋งํ•˜์ง€๋งŒ ์ด๊ฒƒ์€ ๋งค์šฐ ํŽธ๋ฆฌํ•˜์ง€ ์•Š์œผ๋ฉฐ ์•„๋งˆ๋„ react-gateway์™€ ๊ฐ™์€ ์ปจํ…์ŠคํŠธ ๊ธฐ๋ฐ˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ์˜์กดํ•ด์•ผ ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. (๋˜๋Š” ์–ธ๊ธ‰๋œ ์Šฌ๋กฏ ์‹œ์Šคํ…œ).
  • ํฌํ„ธ ๋ฃจํŠธ ๋‚ด์—์„œ ์ˆ˜๋™์œผ๋กœ ์ „ํŒŒ๋ฅผ ์ค‘์ง€ํ•˜์ง€๋งŒ ์œ„์—์„œ ์–ธ๊ธ‰ํ•œ ์›์น˜ ์•Š๋Š” ๋ถ€์ž‘์šฉ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • React ํฌํ„ธ์—์„œ ์ „ํŒŒ๋ฅผ ์ค‘์ง€ํ•˜๋Š” ๊ธฐ๋Šฅ(+1 btw)
  • ํฌํ„ธ์—์„œ ์˜ค๋Š” ์ด๋ฒคํŠธ ํ•„ํ„ฐ๋ง

ํ˜„์žฌ ๋‚ด ์†”๋ฃจ์…˜์€ ์ด๋ฒคํŠธ๋ฅผ ํ•„ํ„ฐ๋งํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

const appRootNode = document.getElementById('root');

const isInPortal = element => isNodeInParent(element, appRootNode);


    handleMouseDown = e => {
      if (!isInPortal(e.target)) {
        return;
      }
      ...
    };

์ด๊ฒƒ์€ ๋ถ„๋ช…ํžˆ ์šฐ๋ฆฌ ๋ชจ๋‘์—๊ฒŒ ์ตœ์ƒ์˜ ์†”๋ฃจ์…˜์ด ์•„๋‹ˆ๋ฉฐ ์ค‘์ฒฉ๋œ ํฌํ„ธ์ด ์žˆ๋Š” ๊ฒฝ์šฐ ๊ทธ๋‹ค์ง€ ์ข‹์ง€ ์•Š์„ ๊ฒƒ์ด์ง€๋งŒ ํ˜„์žฌ ์‚ฌ์šฉ ์‚ฌ๋ก€(ํ˜„์žฌ ์œ ์ผํ•œ ์‚ฌ์šฉ ์‚ฌ๋ก€)์—์„œ๋Š” ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ์ƒˆ๋กœ์šด ์ปจํ…์ŠคํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ๋ณต์žกํ•œ ๋ฆฌํŒฉํ„ฐ๋ง์„ ์ˆ˜ํ–‰ํ•˜๊ณ  ์‹ถ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋‚ด ์†”๋ฃจ์…˜์„ ๊ณต์œ ํ•˜๊ณ  ์‹ถ์—ˆ์Šต๋‹ˆ๋‹ค.

์ด ์Šค๋ ˆ๋“œ์˜ ๋‹ค๋ฅธ ๊ณณ์—์„œ ์–ธ๊ธ‰ํ•œ ๋Œ€๋กœ ์ด๋ฒคํŠธ ๋ฒ„๋ธ”๋ง ์ฐจ๋‹จ์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ๋‚ด๊ฐ€ ๊ฒช๊ณ  ์žˆ๋Š” ๋˜ ๋‹ค๋ฅธ ๊ฐ€์‹œ์ ์ธ ๋ฌธ์ œ๋Š” ๋ฒ„๋ธ”๋ง๋˜์ง€ ์•Š๋Š” onMouseEnter SyntheticEvent์ž…๋‹ˆ๋‹ค. ๋Œ€์‹  ์—ฌ๊ธฐ์— ์„ค๋ช…๋œ ๋Œ€๋กœ from ๊ตฌ์„ฑ ์š”์†Œ์˜ ๊ณตํ†ต ๋ถ€๋ชจ์—์„œ to ๊ตฌ์„ฑ ์š”์†Œ๋กœ ์ด๋™ ํ•ฉ๋‹ˆ๋‹ค . ์ฆ‰, ๋งˆ์šฐ์Šค ํฌ์ธํ„ฐ๊ฐ€ ๋ธŒ๋ผ์šฐ์ € ์ฐฝ ์™ธ๋ถ€์—์„œ ๋“ค์–ด์˜ค๋ฉด DOM ์ƒ๋‹จ์—์„œ createPortal์˜ ๊ตฌ์„ฑ ์š”์†Œ๊นŒ์ง€ ๋ชจ๋“  onMouseEnter ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ํ•ด๋‹น ์ˆœ์„œ๋กœ ํŠธ๋ฆฌ๊ฑฐ๋˜์–ด ๋ชจ๋“  ์ข…๋ฅ˜์˜ ์ด๋ฒคํŠธ๊ฐ€ ์ด๋ฅผ ๋ฐœ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค. unstable_renderSubtreeIntoContainer ์ ์ด ์—†์Šต๋‹ˆ๋‹ค. onMouseEnter ๋Š” ๋ฒ„๋ธ”๋ง๋˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— Portal ์ˆ˜์ค€์—์„œ ์ฐจ๋‹จํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ( onMouseEnter ์ด๋ฒคํŠธ๋Š” ๊ฐ€์ƒ ๊ณ„์ธต ๊ตฌ์กฐ๋ฅผ ์กด์ค‘ํ•˜์ง€ ์•Š๊ณ  ๋ณธ๋ฌธ ๋‚ด์šฉ์„ ํ†ตํ•ด ์ˆœ์„œ๋ฅผ ์ง€์ •ํ•˜์ง€ ์•Š๊ณ  ํ•˜์œ„ ํŠธ๋ฆฌ๋กœ ์ง์ ‘ ๋‚ด๋ ค๊ฐ”๊ธฐ ๋•Œ๋ฌธ์— unstable_renderSubtreeIntoContainer ์—์„œ๋Š” ๋ฌธ์ œ๊ฐ€ ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.)

onMouseEnter ์ด๋ฒคํŠธ๊ฐ€ DOM ๊ณ„์ธต์˜ ๋งจ ์œ„์—์„œ ์ „ํŒŒ๋˜๊ฑฐ๋‚˜ ํฌํ„ธ ํ•˜์œ„ ํŠธ๋ฆฌ๋กœ ์ง์ ‘ ์ „ํ™˜๋˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ์•„์ด๋””์–ด๊ฐ€ ์žˆ๋Š” ์‚ฌ๋žŒ์ด ์žˆ์œผ๋ฉด ์•Œ๋ ค์ฃผ์‹ญ์‹œ์˜ค.

@JasonGore ๋‚˜๋Š” ๋˜ํ•œ์ด ๋™์ž‘์„ ๋ฐœ๊ฒฌํ–ˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด.

div๊ฐ€ onMouseOver๋ฅผ ํŠธ๋ฆฌ๊ฑฐํ•  ๋•Œ ๋ Œ๋”๋ง๋˜๋Š” ์ปจํ…์ŠคํŠธ ๋ฉ”๋‰ด๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ๋ฉ”๋‰ด์˜ ํ•ญ๋ชฉ ์ค‘ ํ•˜๋‚˜๋ฅผ ํด๋ฆญํ•˜์—ฌ createPortal๋กœ ๋ชจ๋‹ฌ์„ ์—ฝ๋‹ˆ๋‹ค. ๋ธŒ๋ผ์šฐ์ € ์ฐฝ ๋ฐ–์œผ๋กœ ๋งˆ์šฐ์Šค๋ฅผ ๊ฐ€์ ธ์˜ค๋ฉด onMouseLeave ์ด๋ฒคํŠธ๊ฐ€ ์ปจํ…์ŠคํŠธ ๋ฉ”๋‰ด๋กœ ์ „ํŒŒ๋˜์–ด ์ปจํ…์ŠคํŠธ ๋ฉ”๋‰ด(๋”ฐ๋ผ์„œ ๋ชจ๋‹ฌ)๊ฐ€ ๋‹ซํž™๋‹ˆ๋‹ค...

์ „์ฒด๋ฅผ ํด๋ฆญํ•  ์ˆ˜ ์žˆ๊ธฐ๋ฅผ ์›ํ–ˆ์ง€๋งŒ(๋งํฌ๋กœ) ๋ชฉ๋ก ํ•ญ๋ชฉ์ด ์žˆ์—ˆ์ง€๋งŒ ํ™•์ธ์„ ์œ„ํ•ด ๋ชจ๋‹ฌ์„ ์—ฌ๋Š” ์ด๋ฆ„ ์•„๋ž˜ ๋ ˆ์ด๋ธ”์˜ ์‚ญ์ œ ๋ฒ„ํŠผ์„ ์›ํ–ˆ๋˜ ๋™์ผํ•œ ๋ฌธ์ œ๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

screenshot 2018-10-31 at 11 42 47

๋‚ด ์œ ์ผํ•œ ํ•ด๊ฒฐ์ฑ…์€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ชจ๋‹ฌ div์—์„œ ๋ฒ„๋ธ”๋ง์„ ๋ฐฉ์ง€ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

// components/Modal.js

onClick(e) {
    e.stopPropagation();
}

return createPortal(
        <div onClick={this.onClick} ...
            ...

๋ชจ๋“  ๋ชจ๋‹ฌ์—์„œ ๋ฒ„๋ธ”๋ง์„ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์•„์ง ๊ทธ๋Ÿฐ ์ผ์ด ์ผ์–ด๋‚˜๊ธธ ์›ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์—†์œผ๋ฏ€๋กœ ์ €์—๊ฒŒ ํšจ๊ณผ์ ์ž…๋‹ˆ๋‹ค.

์ด ์ ‘๊ทผ ๋ฐฉ์‹์— ์ž ์žฌ์ ์ธ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ?

@jnsandrew ~ 50๊ฐ€์ง€ ๋‹ค๋ฅธ ์ด๋ฒคํŠธ ์œ ํ˜•์ด ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์žŠ์ง€ ๋งˆ์„ธ์š” ๐Ÿ™ƒ

์ด๊ฒƒ๋งŒ ์น˜์„ธ์š”. React๊ฐ€ DOM ์ด๋ฒคํŠธ ๋ฒ„๋ธ”๋ง๊ณผ ๋‹ค๋ฅธ ๋ฐฉ์‹์œผ๋กœ ์ž‘๋™ํ•œ๋‹ค๋Š” ๊ฒƒ์ด ์ €์—๊ฒŒ๋Š” ์–ด์ƒ‰ํ•ด ๋ณด์ž…๋‹ˆ๋‹ค.

์ด๊ฒƒ์— +1. ์šฐ๋ฆฌ๋Š” React.createPortal ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ iframe ๋‚ด๋ถ€์—์„œ ๋ Œ๋”๋งํ•˜๊ณ  ์žˆ์œผ๋ฉฐ(์Šคํƒ€์ผ ๋ฐ ์ด๋ฒคํŠธ ๊ฒฉ๋ฆฌ ๋ชจ๋‘์— ๋Œ€ํ•ด) ์ด๋ฒคํŠธ๊ฐ€ ์ƒ์ž ๋ฐ–์œผ๋กœ ๋ฒ„๋ธ”๋ง๋˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์€ ํฐ ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ React์˜ ๋ฐฑ๋กœ๊ทธ์—์„œ 12๋ฒˆ์งธ๋กœ ๋งŽ์ด ์ถ”์ฒœ๋œ ๋ฌธ์ œ์ธ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ ์–ด๋„ ๋ฌธ์„œ๋Š” ๊ทธ๊ฒƒ์— ๋Œ€ํ•ด ์—ด๋ ค ์žˆ์Šต๋‹ˆ๋‹ค https://reactjs.org/docs/portals.html#event -bubbling-through-portals - ๊ทธ๋“ค์€ ๋‹จ์ ์ด๋‚˜ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์„ ์–ธ๊ธ‰ํ•˜์ง€ ์•Š๊ณ  ๋Œ€์‹  "๋” ์œ ์—ฐํ•œ ์ถ”์ƒํ™”๋ฅผ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค. ":

๋ฌธ์„œ๋Š” ์ด๊ฒƒ์ด ๋ฌธ์ œ๋ฅผ ์ผ์œผํ‚ฌ ์ˆ˜ ์žˆ์Œ์„ ์„ค๋ช…ํ•˜๊ณ  ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์„ ์ œ์•ˆํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ œ ๊ฒฝ์šฐ์—๋Š” https://github.com/reactjs/react-modal์„ ์‚ฌ์šฉํ•˜๋Š” ๋งค์šฐ ๊ฐ„๋‹จํ•œ ์‚ฌ์šฉ ์‚ฌ๋ก€์ž…๋‹ˆ๋‹ค. ๋“œ๋กญ๋‹ค์šด๊ณผ ๊ฐ™์€ ํ•ญ๋ชฉ์„ ์—ฌ๋Š” ๋ฒ„ํŠผ์ด ์žˆ์œผ๋ฉฐ ๊ทธ ์•ˆ์— ๋ชจ๋‹ฌ์„ ์ƒ์„ฑํ•˜๋Š” ๋ฒ„ํŠผ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋ชจ๋‹ฌ ๋ฒ„๋ธ”์„ ์ƒ๋‹จ ๋ฒ„ํŠผ์œผ๋กœ ํด๋ฆญํ•˜๋ฉด ์›์น˜ ์•Š๋Š” ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ๋ชจ๋‹ฌ์€ ์‘์ง‘๋ ฅ ์žˆ๋Š” ๊ตฌ์„ฑ ์š”์†Œ๋กœ ์บก์Šํ™”๋˜๊ณ  ํฌํ„ธ ๋ถ€๋ถ„์„ ๋นผ๋‚ด๋ฉด ํ•ด๋‹น ์บก์Šํ™”๊ฐ€ ๊นจ์ง€๊ณ  ์ถ”์ƒํ™”๊ฐ€ ๋ˆ„์ถœ๋ฉ๋‹ˆ๋‹ค. ํ•œ ๊ฐ€์ง€ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์€ ๋ชจ๋‹ฌ์ด ์—ด๋ ค ์žˆ๋Š” ๋™์•ˆ ์ด๋Ÿฌํ•œ ๋ฒ„ํŠผ์„ ๋น„ํ™œ์„ฑํ™”ํ•˜๋„๋ก ํ”Œ๋ž˜๊ทธ๋ฅผ ๋’ค์ง‘๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ฌผ๋ก  ์œ„์—์„œ ์ œ์•ˆํ•œ ๋Œ€๋กœ ์ „ํŒŒ๋ฅผ ์ค‘์ง€ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์–ด๋–ค ๊ฒฝ์šฐ์—๋Š” ๊ทธ๋ ‡๊ฒŒ ํ•˜๊ณ  ์‹ถ์ง€ ์•Š์„ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฒ„๋ธ”๋ง ๋ฐ ์บก์ฒ˜๊ฐ€ ์ผ๋ฐ˜์ ์œผ๋กœ ์–ผ๋งˆ๋‚˜ ๋„์›€์ด ๋˜๋Š”์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค(React๊ฐ€ ๋‚ด๋ถ€์—์„œ ๋ฒ„๋ธ”๋ง์— ์˜์กดํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ์Œ). ํ™•์‹คํžˆ ์Šคํ† ๋ฆฌ๊ฐ€ ์žˆ์ง€๋งŒ ์ฝœ๋ฐฑ์„ ์ „๋‹ฌํ•˜๊ฑฐ๋‚˜ ๋ณด๋‹ค ๊ตฌ์ฒด์ ์ธ ์ด๋ฒคํŠธ(์˜ˆ: redux action) ๋ฒ„๋ธ” ์—… ๋˜๋Š” ์บก์ฒ˜ ๋‹ค์šด๋ณด๋‹ค ๋ถˆํ•„์š”ํ•œ ์ค‘๊ฐœ์ž์˜ ๋ฌด๋ฆฌ๋ฅผ ํ†ตํ•ด ๊ทธ๋Ÿฌํ•œ ์ผ์„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. https://css-tricks.com/dangers-stopping-event-propagation/ ๊ณผ ๊ฐ™์€ ๊ธฐ์‚ฌ๊ฐ€ ์žˆ์œผ๋ฉฐ ์ €๋Š” ์ฃผ๋กœ "์™ธ๋ถ€"๋ฅผ ํด๋ฆญํ•  ๋•Œ ํ•ญ๋ชฉ์„ ๋‹ซ๊ธฐ ์œ„ํ•ด ์‹ ์ฒด๋กœ์˜ ์ „ํŒŒ์— ์˜์กดํ•˜๋Š” ์•ฑ์—์„œ ์ž‘์—…ํ•˜์ง€๋งŒ ์ฐจ๋ผ๋ฆฌ ๋ชจ๋“  ๊ฒƒ ์œ„์— ๋ณด์ด์ง€ ์•Š๋Š” ์˜ค๋ฒ„๋ ˆ์ด๋ฅผ ๋†“๊ณ  ํด๋ฆญํ•˜๋ฉด ๋‹ซ์Šต๋‹ˆ๋‹ค. ๋ฌผ๋ก  ์ด๋Ÿฐ ๋ณด์ด์ง€ ์•Š๋Š” ์˜ค๋ฒ„๋ ˆ์ด๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด React์˜ Portal์„ ์‚ฌ์šฉํ•  ์ˆ˜๋Š” ์—†์—ˆ์ง€๋งŒ...

์—ฌ๊ธฐ์—๋Š” ์œ ์ง€ ๊ด€๋ฆฌ์˜ ์•…๋ชฝ๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ƒˆ ์ด๋ฒคํŠธ๊ฐ€ DOM์— ์ถ”๊ฐ€๋˜๋ฉด ์œ„์—์„œ ๋…ผ์˜ํ•œ ๊ธฐ์ˆ ๋กœ "๋ด‰์ธ๋œ" ํฌํ„ธ์€ ์œ ์ง€ ๊ด€๋ฆฌ์ž๊ฐ€ (๊ด‘๋ฒ”์œ„ํ•œ) ๋ธ”๋ž™๋ฆฌ์ŠคํŠธ์— ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์„ ๋•Œ๊นŒ์ง€ ์ƒˆ ์ด๋ฒคํŠธ๋ฅผ "๋ˆ„์ถœ" ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์„œ ํ•ด๊ฒฐํ•ด์•ผ ํ•  ์ฃผ์š” ์„ค๊ณ„ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ต์ฐจ ํฌํ„ธ ๋ฒ„๋ธ”๋ง์„ ์˜ตํŠธ์ธ ๋˜๋Š” ์˜ตํŠธ์•„์›ƒํ•˜๋Š” ๊ธฐ๋Šฅ์€ ์—ฌ์ „ํžˆ โ€‹โ€‹๋‚˜์—๊ฒŒ ์ตœ๊ณ ์˜ API ์˜ต์…˜์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค. ๊ตฌํ˜„์˜ ์–ด๋ ค์›€์€ ํ™•์‹คํ•˜์ง€ ์•Š์ง€๋งŒ 1๋…„์ด ์ง€๋‚œ ํ›„์—๋„ Tableau์—์„œ ์ด์™€ ๊ด€๋ จ๋œ ํ”„๋กœ๋•์…˜ ๋ฒ„๊ทธ๊ฐ€ ๊ณ„์† ๋ฐœ์ƒํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

๋ชจ๋‹ฌ์˜ ๋‚ด ์–‘์‹์ด ๋‹ค๋ฅธ ์–‘์‹์„ ์ œ์ถœํ•œ ์ด์œ ๋ฅผ ์•Œ์•„๋ณด๊ธฐ ์œ„ํ•ด 2์‹œ๊ฐ„์„ ๋ณด๋‚ด์‹ญ์‹œ์˜ค.
๋งˆ์นจ๋‚ด ๋‚˜๋Š” ๊ทธ ๋ฌธ์ œ ๋•๋ถ„์— ๊ทธ๊ฒƒ์„ ์•Œ์•„ ๋ƒˆ์Šต๋‹ˆ๋‹ค!

๋‚˜๋Š” onSubmit ์ „ํŒŒ๊ฐ€ ํ•„์š”ํ•  ๋•Œ๋ฅผ ์•Œ๊ธฐ ์œ„ํ•ด ์ •๋ง ๊ณ ๊ตฐ๋ถ„ํˆฌํ•ฉ๋‹ˆ๋‹ค. ๊ธฐ๋Šฅ๋ณด๋‹ค๋Š” ๋ฒ„๊ทธ์— ๋” ๊ฐ€๊น์Šต๋‹ˆ๋‹ค.

์ตœ์†Œํ•œ ๋ฐ˜์‘ ๋ฌธ์„œ์— ๊ฒฝ๊ณ  ์ •๋ณด๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์€ ๊ฐ€์น˜๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ฐ™์€:
ํฌํ„ธ์„ ํ†ตํ•œ ์ด๋ฒคํŠธ ๋ฒ„๋ธ”๋ง์€ ํ›Œ๋ฅญํ•œ ๊ธฐ๋Šฅ์ด์ง€๋งŒ ์ผ๋ถ€ ์ด๋ฒคํŠธ ์ „ํŒŒ๋ฅผ ๋ฐฉ์ง€ํ•˜๋ ค๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. onSubmit={(e) => {e.stopPropagation()}} ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ์ด๋ฅผ ๋‹ฌ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ๋„ +1. ์šฐ๋ฆฌ๋Š” ๋ชจ๋‹ฌ์„ ๋ณด์—ฌ์ฃผ๋Š” ํด๋ฆญ ๊ฐ€๋Šฅํ•œ ํ…์ŠคํŠธ์™€ ํ•จ๊ป˜ draftjs๋ฅผ ๋งŽ์ด ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ํฌ์ปค์Šค, ์„ ํƒ, ๋ณ€๊ฒฝ, ํ‚ค ๋ˆ„๋ฅด๊ธฐ์™€ ๊ฐ™์€ ๋ชจ๋‹ฌ์˜ ๋ชจ๋“  ์ด๋ฒคํŠธ๋Š” ์˜ค๋ฅ˜๋กœ draftjs๋ฅผ ํญ๋ฐœ์‹œํ‚ต๋‹ˆ๋‹ค.

IMO, ์ด๋ฒคํŠธ ํ”„๋ก์‹œ ๋™์ž‘์€ ๊ทผ๋ณธ์ ์œผ๋กœ ์†์ƒ๋˜์—ˆ์ง€๋งŒ(๋‚˜์—๊ฒŒ๋„ ๋ฒ„๊ทธ๊ฐ€ ๋ฐœ์ƒํ•จ) ์ด๊ฒƒ์ด ๋…ผ๋ž€์˜ ์—ฌ์ง€๊ฐ€ ์žˆ์Œ์„ ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์Šค๋ ˆ๋“œ๋Š” ์ปจํ…์ŠคํŠธ๊ฐ€ ์•„๋‹Œ ์ด๋ฒคํŠธ๊ฐ€ ์•„๋‹Œ ์ปจํ…์ŠคํŠธ ๋ฅผ ์›œํ™€ํ•˜๋Š” ํฌํ„ธ์ด ํ•„์š”ํ•˜๋‹ค๋Š” ๊ฒƒ์„ ๊ฐ•๋ ฅํ•˜๊ฒŒ ์ œ์•ˆ ํ•ฉ๋‹ˆ๋‹ค . ํ•ต์‹ฌ ํŒ€์ด ๋™์˜ํ•ฉ๋‹ˆ๊นŒ? ์–ด๋Š ์ชฝ์ด๋“ , ์—ฌ๊ธฐ์—์„œ ๋‹ค์Œ ๋‹จ๊ณ„๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

ํฌํ„ธ์—์„œ ์ด๋ฒคํŠธ๋ฅผ ์ „ํŒŒํ•˜๋Š” ๊ฒƒ์ด ์˜๋„๋œ ๋™์ž‘์ธ ์ด์œ ๋ฅผ ์ •๋ง ์•Œ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์ „ํŒŒ์˜ ์ฃผ์š” ๊ฐœ๋…์— ์™„์ „ํžˆ ๋ฐ˜๋Œ€๋ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ํฌํ„ธ์ด ์ด๋Ÿฐ ์ข…๋ฅ˜์˜ ์ผ(์ˆ˜๋™ ์ค‘์ฒฉ, ์ด๋ฒคํŠธ ์ „ํŒŒ ๋“ฑ)์„ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด ์ •ํ™•ํžˆ ๋งŒ๋“ค์–ด์กŒ๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค.

์š”์†Œ ํŠธ๋ฆฌ ๊ทผ์ฒ˜์— ํฌํ„ธ์„ ๋ฐฐ์น˜ํ•˜๋ฉด ์ด๋ฒคํŠธ๊ฐ€ ์ „ํŒŒ๋œ๋‹ค๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

class SomeComponent extends React.Component<any, any> {
  render() {
    return <>
      <div className="some-tree">
        // Portal here will bubble events
      </div>
      // Portal here will also bubble events, just checked
    </>
  }
}

์ด ๊ธฐ๋Šฅ ์š”์ฒญ์— ๋Œ€ํ•ด +1

DOM์—์„œ ์ด๋ฒคํŠธ๋Š” DOM ํŠธ๋ฆฌ๋ฅผ ๋ฒ„๋ธ”๋งํ•ฉ๋‹ˆ๋‹ค. React์—์„œ ์ด๋ฒคํŠธ๋Š” ๊ตฌ์„ฑ ์š”์†Œ ํŠธ๋ฆฌ๋ฅผ ๋ฒ„๋ธ”๋งํ•ฉ๋‹ˆ๋‹ค.

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

์—ฌ๊ธฐ์—์„œ ํ™œ๋ฐœํ•œ ๋…ผ์˜๋ฅผ ํ†ตํ•ด ๋‘ ๊ฐ€์ง€ ํ–‰๋™์„ createPortal ๋Š” "์ผ๋ฐ˜ DOM" ์ปจํ…Œ์ด๋„ˆ ๋…ธ๋“œ ๋‚ด๋ถ€์˜ React ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ๋ Œ๋”๋งํ•˜๊ธฐ ๋•Œ๋ฌธ์— React์˜ ํ•ฉ์„ฑ ์ด๋ฒคํŠธ๊ฐ€ Portal์—์„œ ์ผ๋ฐ˜ DOM ํŠธ๋ฆฌ ์œ„๋กœ ์ „ํŒŒ๋˜๋Š” ๊ฒƒ์€ ์ž‘๋™ํ•˜์ง€ ์•Š์„ ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

Portal์ด ์ถœ์‹œ๋œ ์ง€ ์˜ค๋ž˜๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ธฐ๋ณธ ๋™์ž‘์„ "ํฌํ„ธ ๊ฒฝ๊ณ„๋ฅผ ๋„˜์–ด ์ „ํŒŒํ•˜์ง€ ์•Š์Œ"์œผ๋กœ ๋ณ€๊ฒฝํ•˜๊ธฐ์—๋Š” ๋„ˆ๋ฌด ๋Šฆ์—ˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ง€๊ธˆ๊นŒ์ง€ ๋ชจ๋“  ๋…ผ์˜๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ, ๋‚ด ๊ฐ„๋‹จํ•œ ์ œ์•ˆ์€ (์—ฌ์ „ํžˆ)์ž…๋‹ˆ๋‹ค : createPortal์— ์˜ต์…˜ ํ”Œ๋ž˜๊ทธ๋ฅผ ์ถ”๊ฐ€ ๊ฒƒ์„ ๋ฐฉ์ง€ ํฌํ„ธ ๊ฒฝ๊ณ„ ๊ณผ๊ฑฐ์˜ ์–ด๋–ค ์ด๋ฒคํŠธ ์ „ํŒŒ.

๋” ๊ฐ•๋ ฅํ•œ ๊ฒƒ์€ ๊ฒฝ๊ณ„๋ฅผ "ํŒŒ์ง€"ํ•˜๋Š” ๊ฒƒ์„ ํ—ˆ์šฉํ•ด์•ผ ํ•˜๋Š” ์ด๋ฒคํŠธ์˜ ํ™”์ดํŠธ๋ฆฌ์ŠคํŠธ๋ฅผ ์ œ๊ณตํ•˜๋Š” ๋™์‹œ์— ๋‚˜๋จธ์ง€๋Š” ์ค‘์ง€ํ•˜๋Š” ๊ธฐ๋Šฅ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@gaearon React ํŒ€์ด ์‹ค์ œ๋กœ ์ด๊ฒƒ์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ์‹œ์ ์— ์žˆ์Šต๋‹ˆ๊นŒ? ์ด๊ฒƒ์€ ์ƒ์œ„ 10๊ฐœ ๋ฌธ์ œ์ด์ง€๋งŒ ๊ฝค ์˜ค๋žซ๋™์•ˆ ์ด์— ๋Œ€ํ•ด ์•„๋ฌด ์†Œ์‹๋„ ๋“ฃ์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค.

์ด์— ๋Œ€ํ•œ ์ง€์›์„ ์ถ”๊ฐ€ํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. React ์ปจํ…์ŠคํŠธ์™€ DOM ์ด๋ฒคํŠธ ๋ฒ„๋ธ”๋ง์„ ๋ชจ๋‘ ํฌํ„ธ๋งํ•˜๋Š” ๊ฒƒ์ด ์ปจํ…์ŠคํŠธ๋งŒ ํฌํ„ธ๋งํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ๊ฐœ๋…์ ์œผ๋กœ ๋” ํ•ฉ๋ฆฌ์ ์ด๋ผ๊ณ  ์ฃผ์žฅํ•˜๋Š” ์ž‘๋…„์˜ @sebmarkbage ์˜๊ฒฌ์— ๋™์˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

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

DOM ์ด๋ฒคํŠธ ๋ฒ„๋ธ”๋ง์€ ์ฃผ๋กœ DOM ์ด๋ฒคํŠธ๋ฅผ DOM ๋Œ€์ƒ๊ณผ ์ผ์น˜์‹œํ‚ค๋Š” ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค. ๋ชจ๋“  ํด๋ฆญ์€ ์‹ค์ œ๋กœ ์ „์ฒด ์ค‘์ฒฉ ์š”์†Œ ์ง‘ํ•ฉ์— ๋Œ€ํ•œ ํด๋ฆญ์ž…๋‹ˆ๋‹ค. ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ DOM์˜ ์˜ˆ์ธก ๊ฐ€๋Šฅํ•œ ๋น„ํŠธ๋ฅผ ๋ Œ๋”๋งํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋Š” ์ž‘์€ ๊ฐœ์ธ ๋„์šฐ๋ฏธ ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ์•„๋‹Œ ํ•œ ๋†’์€ ์ˆ˜์ค€์˜ ์œ„์ž„ ๋ฉ”์ปค๋‹ˆ์ฆ˜์ธ IMO๋กœ ๊ฐ„์ฃผ๋˜์ง€ ์•Š์œผ๋ฉฐ DOM ์ด๋ฒคํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ React ๊ตฌ์„ฑ ์š”์†Œ ๊ฒฝ๊ณ„๋ฅผ ๋„˜์–ด ์œ„์ž„ํ•˜๋Š” ๊ฒƒ์€ ํ›Œ๋ฅญํ•œ ์บก์Šํ™”๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค.

event.target === event.currentTarget์€ ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด๊ฒƒ์€ ์ •๋ง ๋จธ๋ฆฌ๊ฐ€ ์•„ํ”„๋‹ค.

์ด ๋น„ํŠธ ๋‚˜๋ฅผ ์˜ค๋Š˜ ์‚ฌ์šฉ ํŒ ์˜ค๋ฒ„ ๊ตฌ์„ฑ ์š”์†Œ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ํ•˜๋Š” ๋™์•ˆ unstable_renderSubtreeIntoContainer ์‚ฌ์šฉํ•˜๊ธฐ createPortal . ๋ฌธ์ œ์˜ ๊ตฌ์„ฑ ์š”์†Œ์—๋Š” ๋“œ๋ž˜๊ทธ ๊ฐ€๋Šฅํ•œ ์š”์†Œ๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์œผ๋ฉฐ ๋‹ค๋ฅธ ๋“œ๋ž˜๊ทธ ๊ฐ€๋Šฅํ•œ ์š”์†Œ์˜ ํ•˜์œ„ ์š”์†Œ๋กœ ๋ Œ๋”๋ง๋ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์ƒ์œ„ ์š”์†Œ์™€ ํŒ์˜ค๋ฒ„ ์š”์†Œ ๋ชจ๋‘์— ๋งˆ์šฐ์Šค ๋ฐ ํ„ฐ์น˜ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์œผ๋ฉฐ ํฌํ„ธ์˜ ํŒ์˜ค๋ฒ„์™€ ์ƒํ˜ธ ์ž‘์šฉํ•  ๋•Œ ๋‘˜ ๋‹ค ์‹คํ–‰๋˜๊ธฐ ์‹œ์ž‘ํ–ˆ์Œ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

unstable_renderSubtreeIntoContainer ๊ฐ€ ๋” ์ด์ƒ ์‚ฌ์šฉ๋˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— (?) ๋Œ€์ฒด ์†”๋ฃจ์…˜์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์œ„์— ์ œ์‹œ๋œ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ• ์ค‘ ์–ด๋Š ๊ฒƒ๋„ ์‹คํ–‰ ๊ฐ€๋Šฅํ•œ ์žฅ๊ธฐ ์†”๋ฃจ์…˜์œผ๋กœ ๋ณด์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

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

IMO๋Š” ํฌํ„ธ์—์„œ ์ปจํ…์ŠคํŠธ์— ๋Œ€ํ•œ ์•ก์„ธ์Šค๋ฅผ ์ œ๊ณตํ•˜์ง€๋งŒ ์ด๋ฒคํŠธ๋ฅผ ๋ฒ„๋ธ”๋งํ•˜์ง€ ์•Š๊ธฐ๋ฅผ ์›ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋” ๋งŽ์Šต๋‹ˆ๋‹ค. Angular 1.x๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ $scope ๋ฐ ํ…œํ”Œ๋ฆฟ ๋ฌธ์ž์—ด์„ ์‚ฌ์šฉํ•˜์—ฌ ํ•ด๋‹น ํ…œํ”Œ๋ฆฟ์„ ์ปดํŒŒ์ผ/๋ Œ๋”๋งํ•˜๊ณ  ๋ณธ๋ฌธ์— ์ถ”๊ฐ€ํ•˜๋Š” ์ž์ฒด ํŒ์—… ์„œ๋น„์Šค๋ฅผ ์ž‘์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ํ•ด๋‹น ์„œ๋น„์Šค๋กœ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋ชจ๋“  ํŒ์—…/๋ชจ๋‹ฌ/๋“œ๋กญ๋‹ค์šด์„ ๊ตฌํ˜„ํ–ˆ์œผ๋ฉฐ ์ด๋ฒคํŠธ ๋ฒ„๋ธ”๋ง์ด ์—†๋Š” ๊ฒƒ์„ ํ•œ ๋ฒˆ๋„ ๋†“์นœ ์ ์ด ์—†์Šต๋‹ˆ๋‹ค.

stopPropagation() ํ•ด๊ฒฐ ๋ฐฉ๋ฒ• ์€ window ๊ธฐ๋ณธ ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๊ฐ€ ํŠธ๋ฆฌ๊ฑฐ๋˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค(์ด ๊ฒฝ์šฐ react-dnd-html5-backend ์— ์˜ํ•ด ์ถ”๊ฐ€๋จ).

๋‹ค์Œ์€ ๋ฌธ์ œ์— ๋Œ€ํ•œ ์ตœ์†Œํ•œ์˜ ์žฌํ˜„์ž…๋‹ˆ๋‹ค. https://codepen.io/mogel/pen/xxKRPbQ

ํฌํ„ธ ์ „์ฒด์—์„œ ํ•ฉ์„ฑ ๋ฒ„๋ธ”๋ง์„ ๋ฐฉ์ง€ํ•  ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•  ๊ณ„ํš์ด ์—†๋Š” ๊ฒฝ์šฐ ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ๊ธฐ๋ณธ ์ด๋ฒคํŠธ ๋ฒ„๋ธ”๋ง์„ ์ค‘๋‹จํ•˜์ง€ ์•Š๋Š” ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์„ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ?

stopPropagation() ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์€ ์ฐฝ์˜ ๊ธฐ๋ณธ ์ด๋ฒคํŠธ ์ˆ˜์‹ ๊ธฐ๊ฐ€ ํŠธ๋ฆฌ๊ฑฐ๋˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค.

์˜ณ์€. :(

ํฌํ„ธ ์ „์ฒด์—์„œ ํ•ฉ์„ฑ ๋ฒ„๋ธ”๋ง์„ ๋ฐฉ์ง€ํ•  ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•  ๊ณ„ํš์ด ์—†๋Š” ๊ฒฝ์šฐ

ํ•ต์‹ฌ ํŒ€์˜ ์นจ๋ฌต์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ๋‚˜์™€ ์ด ์Šค๋ ˆ๋“œ์˜ ๋‹ค๋ฅธ ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์€ ๊ทธ๋Ÿฌํ•œ ๊ณ„ํš์ด _์ •๋ง ํฌ๋งํ•ฉ๋‹ˆ๋‹ค_.

์•„๋งˆ๋„ ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ๊ธฐ๋ณธ ์ด๋ฒคํŠธ ๋ฒ„๋ธ”๋ง์„ ์ค‘๋‹จํ•˜์ง€ ์•Š๋Š” ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์„ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ?

์šฐ๋ฆฌ ํŒ€์˜ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์€ ์ด ๋ˆˆ์— ๋„๋Š” ๋ฌธ์ œ ๋•Œ๋ฌธ์— ํฌํ„ธ์„ ์™„์ „ํžˆ ๊ธˆ์ง€ํ•˜๋Š” ๊ฒƒ์ด์—ˆ์Šต๋‹ˆ๋‹ค. ์•ฑ์˜ ๋‹ค๋ฅธ ์ปจํ…์ŠคํŠธ ๋‚ด์— ์žˆ๋Š” ์ปจํ…Œ์ด๋„ˆ์— ํ›„ํฌ๊ฐ€ ์žˆ๋Š” ์ฐฝ์„ ์ œ๊ณตํ•˜๋ฏ€๋กœ ๋ฃจํŠธ ์ˆ˜์ค€ ์ปจํ…์ŠคํŠธ๋ฅผ ๋ฌด๋ฃŒ๋กœ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ์ˆ˜๋™์œผ๋กœ ์ „๋‹ฌํ•˜๋Š” ๋‹ค๋ฅธ ๋ชจ๋“  ๊ฒƒ. ์ข‹์ง€๋Š” ์•Š์ง€๋งŒ ๋ฌด์˜๋ฏธํ•œ ๋‘๋”์ง€ ๋•Œ๋ฆฌ๊ธฐ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋ณด๋‹ค ๋‚ซ์Šต๋‹ˆ๋‹ค.

ํ•ต์‹ฌ ํŒ€์˜ ๋ˆ„๊ตฐ๊ฐ€ ๊ฐ€ ๋งˆ์ง€๋ง‰์œผ๋กœ ์‘๋‹ต ํ•œ ์ง€ 17๊ฐœ์›”์ด ์ง€๋‚ฌ์Šต๋‹ˆ๋‹ค. ์•„๋งˆ๋„ ping์ด ์ด ๋ฌธ์ œ์— ์ฃผ์˜๋ฅผ ๊ธฐ์šธ์ผ ์ˆ˜ ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค :) @sebmarkbage ๋˜๋Š” @gaearon

์šฐ๋ฆฌ ํŒ€์˜ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์€ ์ด ๋ˆˆ์— ๋„๋Š” ๋ฌธ์ œ ๋•Œ๋ฌธ์— ํฌํ„ธ์„ ์™„์ „ํžˆ ๊ธˆ์ง€ํ•˜๋Š” ๊ฒƒ์ด์—ˆ์Šต๋‹ˆ๋‹ค. ์•ฑ์˜ ๋‹ค๋ฅธ ์ปจํ…์ŠคํŠธ ๋‚ด์— ์žˆ๋Š” ์ปจํ…Œ์ด๋„ˆ์— ํ›„ํฌ๊ฐ€ ์žˆ๋Š” ์ฐฝ์„ ์ œ๊ณตํ•˜๋ฏ€๋กœ ๋ฃจํŠธ ์ˆ˜์ค€ ์ปจํ…์ŠคํŠธ๋ฅผ ๋ฌด๋ฃŒ๋กœ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ์ˆ˜๋™์œผ๋กœ ์ „๋‹ฌํ•˜๋Š” ๋‹ค๋ฅธ ๋ชจ๋“  ๊ฒƒ. ์ข‹์ง€๋Š” ์•Š์ง€๋งŒ ๋ฌด์˜๋ฏธํ•œ ๋‘๋”์ง€ ๋•Œ๋ฆฌ๊ธฐ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋ณด๋‹ค ๋‚ซ์Šต๋‹ˆ๋‹ค.

๊ณ„๋‹จ์‹ ์†Œํ’ˆ์— ์˜์กดํ•˜์ง€ ์•Š๊ณ  ์†Œํ’ˆ์„ ํ†ตํ•ด "๊ฐ€์งœ ํฌํ„ธ"๋กœ ์ปจํ…์ŠคํŠธ๋ฅผ ์ „๋‹ฌํ•˜๋Š” ์ผ๋ฐ˜์ ์ธ ์ ‘๊ทผ ๋ฐฉ์‹์€ ์ƒ๊ฐํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

https://github.com/reakit/reakit ์—์„œ ์ด ๋ฌธ์ œ์™€ ๊ด€๋ จ๋œ ์ˆ˜๋งŽ์€ ๋ฒ„๊ทธ๋ฅผ ๋ฐœ๊ฒฌํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” React Portal์„ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋ฉฐ ํฌํ„ธ์—์„œ ์ƒ์œ„ ๊ตฌ์„ฑ ์š”์†Œ๋กœ ์ด๋ฒคํŠธ ๋ฒ„๋ธ”๋ง์„ ์›ํ–ˆ๋˜ ๋‹จ์ผ ์‚ฌ๋ก€๋ฅผ ์ƒ๊ฐํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

๋‚ด ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์€ ๋ถ€๋ชจ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ ๋‚ด์—์„œ ํ™•์ธํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

event.currentTarget.contains(event.target);

๋˜๋Š” ๋Œ€์‹  ๊ธฐ๋ณธ ์ด๋ฒคํŠธ ์‚ฌ์šฉ:

const onClick = () => {};
React.useEffect(() => {
  ref.current.addEventListener("click", onClick);
  return () => ref.current.removeEventListener("click", onClick);
});

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

์ด๋ฒคํŠธ ๋ฒ„๋ธ”๋ง์„ ๋น„ํ™œ์„ฑํ™”ํ•˜๋Š” ์˜ต์…˜์€ ์ด๋Ÿฌํ•œ ๋ชจ๋“  ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋‚˜๋Š” window ์ด๋ฒคํŠธ์˜ ํด๋ก ์„ ๋‹ค์‹œ ํŠธ๋ฆฌ๊ฑฐํ•˜๋ฉด์„œ React ๋ฒ„๋ธ”๋ง์„ ์ฐจ๋‹จํ•˜๋Š” ๋ฐ˜ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ• ์„ ํ•จ๊ป˜ ํ•ดํ‚นํ–ˆ์Šต๋‹ˆ๋‹ค. OSX์˜ Chrome, Firefox ๋ฐ Safari์—์„œ ์ž‘๋™ํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๋ณด์ด์ง€๋งŒ IE11์€ event.target ๋ฅผ ์ˆ˜๋™์œผ๋กœ ์„ค์ •ํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. ์ง€๊ธˆ๊นŒ์ง€๋Š” ๋งˆ์šฐ์Šค, ํฌ์ธํ„ฐ, ํ‚ค๋ณด๋“œ ๋ฐ ํœ  ์ด๋ฒคํŠธ์—๋งŒ ๊ด€์‹ฌ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋“œ๋ž˜๊ทธ ์ด๋ฒคํŠธ๋ฅผ ๋ณต์ œํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ํ™•์‹คํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋ถˆํ–‰ํžˆ๋„ IE11 ์ง€์›์ด ํ•„์š”ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ฝ”๋“œ๋ฒ ์ด์Šค์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์ง€๋งŒ ๋‹ค๋ฅธ ์‚ฌ๋žŒ์ด ์ž์‹ ์˜ ์šฉ๋„์— ๋งž๊ฒŒ ์กฐ์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์ด ํŠนํžˆ ๋งˆ์Œ์„ ํ˜ผ๋ž€์Šค๋Ÿฝ๊ฒŒ ๋งŒ๋“œ๋Š” ๊ฒƒ์€ '๊ธฐ๋ณธ' ๋™์ž‘์ด ๊ตฌ์„ฑ ์š”์†Œ ํŠธ๋ฆฌ๋ฅผ ๋‹ค์‹œ _down_ ๊ฑฐํ’ˆ์ด ๋ฐœ์ƒํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋‹ค์Œ ๋‚˜๋ฌด๋ฅผ ๊ฐ€์ ธ ๊ฐ€๋ผ.

<Link>
   <Menu (portal)>
      <form onSubmit={...}>
         <button type="submit">

์ด ์ •ํ™•ํ•œ ๊ตฌ์„ฑ ์š”์†Œ ์กฐํ•ฉ์„ ์‚ฌ์šฉํ•˜๋ฉด ์ œ์ถœ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๊ฑฐ๋‚˜ ์–‘์‹ ๋‚ด๋ถ€์˜ ์ž…๋ ฅ ํ•„๋“œ์—์„œ Enter ํ‚ค๋ฅผ ๋ˆ„๋ฅด๋”๋ผ๋„ ๋‚ด ์–‘์‹์˜ onSubmit ๊ฐ€ ํ˜ธ์ถœ๋˜์ง€ ์•Š๋Š” ์ด์œ ์— ๋Œ€ํ•ด ๋ช‡ ์‹œ๊ฐ„ ๋™์•ˆ ๊ณ ๋ฏผํ–ˆ์Šต๋‹ˆ๋‹ค.

๋งˆ์ง€๋ง‰์œผ๋กœ, React Router Link ๊ตฌ์„ฑ ์š”์†Œ์— e.preventDefault() ๋ฅผ ์‹คํ–‰ํ•˜์—ฌ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๋‹ค์‹œ ๋กœ๋“œ๋˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜๋Š” onClick ๊ตฌํ˜„์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ฐœ๊ฒฌํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด๊ฒƒ์€ ์–‘์‹์„ ์ œ์ถœํ•˜๊ฒŒ ๋˜๋Š” ์ œ์ถœ ๋ฒ„ํŠผ ํด๋ฆญ์˜ ๊ธฐ๋ณธ ๋™์ž‘๋„ ์ฐจ๋‹จํ•˜๋Š” ๋ถˆํ–‰ํ•œ ๋ถ€์ž‘์šฉ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์˜ค๋Š˜ ๋ฐฐ์šด ๊ฒƒ์€ ์ œ์ถœ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋Š” ๊ธฐ๋ณธ ๋™์ž‘์œผ๋กœ onSubmit์ด ์‹ค์ œ๋กœ ๋ธŒ๋ผ์šฐ์ €์— ์˜ํ•ด ํ˜ธ์ถœ๋œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. Enter๋ฅผ ๋ˆŒ๋Ÿฌ๋„ ์ œ์ถœ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜์—ฌ ์–‘์‹ ์ œ์ถœ์„ ํŠธ๋ฆฌ๊ฑฐํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ์ด๋ฒคํŠธ ๋ฒ„๋ธ”๋ง ์ˆœ์„œ๊ฐ€ ์ด๊ฒƒ์„ ์ •๋ง ์ด์ƒํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  1. <input> [ํ‚ค ๋ˆ„๋ฅด๊ธฐ]
  2. <button type="submit"> [์‹œ๋ฎฌ๋ ˆ์ด์…˜ ํด๋ฆญ]
  3. <Menu> [์ด๋ฒคํŠธ๊ฐ€ ํฌํ„ธ ์™ธ๋ถ€๋กœ ์ „ํŒŒ๋จ]
  4. <Link> [์ƒ์œ„ Link ์ „ํŒŒ๋จ ]
  5. <Link> [ e.preventDefault() ํ˜ธ์ถœ ]
  6. => ์ œ์ถœ ๋ฒ„ํŠผ ํด๋ฆญ์— ๋Œ€ํ•œ ๊ธฐ๋ณธ ๋ธŒ๋ผ์šฐ์ € ์‘๋‹ต์ด ์ทจ์†Œ๋จ
  7. => ์–‘์‹์ด ์ œ์ถœ๋˜์ง€ ์•Š์Œ

์ด๊ฒƒ์€ ์ด๋ฏธ DOM์—์„œ ๋ฒ„ํŠผ๊ณผ ์–‘์‹์„ ์ „๋‹ฌํ–ˆ์ง€๋งŒ Link ๋Š” ์ด๊ฒƒ๊ณผ ์•„๋ฌด ๊ด€๋ จ์ด ์—†์œผ๋ฉฐ ์ด ๋™์ž‘์„ ์ „ํ˜€ ์ฐจ๋‹จํ•  ์˜๋„๋„ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.

๋‚˜๋ฅผ ์œ„ํ•œ ์†”๋ฃจ์…˜(๋ˆ„๊ตฐ๊ฐ€ ๋™์ผํ•œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๊ฒฝ์šฐ)์€ onClick={e => e.stopPropagation()} ๋กœ div์˜ <Menu> ์ฝ˜ํ…์ธ ๋ฅผ ๋ž˜ํ•‘ํ•˜๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ์†”๋ฃจ์…˜์ด์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ œ ์š”์ ์€ ๋ฌธ์ œ๋ฅผ ์ถ”์ ํ•˜๋Š” ๋ฐ ๋งŽ์€ ์‹œ๊ฐ„์„ ํ—ˆ๋น„ํ–ˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ ํ–‰๋™์ด ์ •๋ง ์ง๊ด€์ ์ด์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

๋‚˜๋ฅผ ์œ„ํ•œ ์†”๋ฃจ์…˜(๋ˆ„๊ตฐ๊ฐ€ ๋™์ผํ•œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๊ฒฝ์šฐ)์€ onClick={e => e.stopPropagation()} ๋กœ div์˜ <Menu> ์ฝ˜ํ…์ธ ๋ฅผ ๋ž˜ํ•‘ํ•˜๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ์†”๋ฃจ์…˜์ด์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ œ ์š”์ ์€ ๋ฌธ์ œ๋ฅผ ์ถ”์ ํ•˜๋Š” ๋ฐ ๋งŽ์€ ์‹œ๊ฐ„์„ ํ—ˆ๋น„ํ–ˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ ํ–‰๋™์ด ์ •๋ง ์ง๊ด€์ ์ด์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

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

ํฌํ„ธ์—์„œ mouseenter ์˜ˆ๊ธฐ์น˜ ์•Š๊ฒŒ ๋ฒ„๋ธ”๋ง๋˜๋Š” ๋‹ค๋ฅธ ๋ฌธ์ œ๋ฅผ ๋””๋ฒ„๊น…ํ•˜๋Š” ๋ฐ ๋ฉฐ์น ์„ ๋ณด๋ƒˆ์Šต๋‹ˆ๋‹ค. ํฌํ„ธ div์— onMouseEnter={e => e.stopPropagation()} ๊ฐ€ ์žˆ์–ด๋„ ์ด๋ฒคํŠธ๋Š” https://github.com/facebook/react/issues/11387#issuecomment -340009465(์ฒซ ๋ฒˆ์งธ ์ด ๋ฌธ์ œ์— ๋Œ€ํ•œ ์˜๊ฒฌ). mouseenter / mouseleave ๋Š” ์• ์ดˆ์— ๊ฑฐํ’ˆ์ด ๋‚˜์ง€ ์•Š์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค...

์•„๋งˆ๋„ ๋” ์ด์ƒํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. mouseenter ํ•ฉ์„ฑ ์ด๋ฒคํŠธ ๋ฒ„๋ธ”์ด ํฌํ„ธ์—์„œ ๋ฒ„ํŠผ์œผ๋กœ ์—ฐ๊ฒฐ๋˜๋Š” ๊ฒƒ์„ ๋ณผ ๋•Œ e.nativeEvent.type ๋Š” mouseout ์ž…๋‹ˆ๋‹ค. React๋Š” ๋ฒ„๋ธ”๋ง ๋„ค์ดํ‹ฐ๋ธŒ ์ด๋ฒคํŠธ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๋ฒ„๋ธ”๋ง๋˜์ง€ ์•Š๋Š” ํ•ฉ์„ฑ ์ด๋ฒคํŠธ๋ฅผ ํŠธ๋ฆฌ๊ฑฐํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. stopPropagation ๊ฐ€ ํ•ฉ์„ฑ ์ด๋ฒคํŠธ์—์„œ ํ˜ธ์ถœ๋˜์—ˆ์Œ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ .

@gaearon @trueadm ์ด ๋ฌธ์ œ๋Š” ํ˜„์žฌ 2๋…„ ๋™์•ˆ ์ผ๊ด€๋˜๊ณ  ์—„์ฒญ๋‚œ ์ขŒ์ ˆ์„ ์•ผ๊ธฐํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด ์Šค๋ ˆ๋“œ๋Š” React์—์„œ ๊ฐ€์žฅ ํ™œ๋ฐœํ•œ ์ด์Šˆ ์ค‘ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค. ์ œ๋ฐœ , ํŒ€์—์„œ ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ์—ฌ๊ธฐ์— ๊ธฐ์—ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

์ œ ๊ฒฝ์šฐ์—๋Š” Button์„ ํด๋ฆญํ•˜์—ฌ Window ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์—ด๋ฉด Window๋ฅผ ํด๋ฆญํ•˜๋ฉด ์ƒํƒœ ๋ณ€๊ฒฝ์„ ์ผ์œผํ‚จ ๋ฒ„ํŠผ์ด ํด๋ฆญ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์ฐฝ์ด ์‚ฌ๋ผ์ง‘๋‹ˆ๋‹ค.

์ €๋Š” React๋ฅผ ์ฒ˜์Œ ์ ‘ํ•˜๊ณ  jQuery์™€ vanillia JS๋ฅผ ์ฃผ๋กœ ์‚ฌ์šฉํ•˜์ง€๋งŒ ์ด๊ฒƒ์€ ๋งˆ์Œ์„ ์šธ๋ฆฌ๋Š” ๋ฒ„๊ทธ์ž…๋‹ˆ๋‹ค. ์ด ๋™์ž‘์ด ์˜ˆ์ƒ๋˜๋Š” ๊ฒฝ์šฐ๊ฐ€ 1% ์ •๋„ ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@diegohaz ์˜ ๋‘ ๊ฐ€์ง€ ์†”๋ฃจ์…˜ ์ด ๋งˆ์Œ ์— ๋“ค์ง€๋งŒ ์—ฌ์ „ํžˆ createPortal ์ด๋ฒคํŠธ ๋ฒ„๋ธ”๋ง์„ ์ค‘์ง€ํ•˜๋Š” ์˜ต์…˜์ด ์žˆ์–ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๋‚ด ํŠน์ • ์‚ฌ์šฉ ์‚ฌ๋ก€๋Š” ๋„๊ตฌ ์„ค๋ช…์˜ onMouseLeave ๋ฐ onMouseEnter ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ํ•ด๋‹น ํ•˜์œ„ ํฌํ„ธ ํ•˜์œ„ ํ•ญ๋ชฉ์— ์˜ํ•ด ํŠธ๋ฆฌ๊ฑฐ๋˜๋Š” ๊ฒฝ์šฐ์˜€์Šต๋‹ˆ๋‹ค. ๊ธฐ๋ณธ ์ด๋ฒคํŠธ๋Š” ํฌํ„ธ ํ•˜์œ„ ํ•ญ๋ชฉ์ด DOM ํ•˜์œ„ ํ•ญ๋ชฉ์ด ์•„๋‹ˆ๋ฏ€๋กœ ๋ฌด์‹œํ•˜์—ฌ ์ด ๋ฌธ์ œ๋ฅผ ์ˆ˜์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.

ํฌํ„ธ์—์„œ ๋ฒ„๋ธ”๋ง์„ ์ค‘์ง€ํ•˜๋Š” ์˜ต์…˜์˜ ๊ฒฝ์šฐ +1์ž…๋‹ˆ๋‹ค. ํฌํ„ธ์„ ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๊ฐ€ ์‹œ์ž‘๋˜๋Š” ๊ตฌ์„ฑ ์š”์†Œ์— ๋Œ€ํ•œ ํ˜•์ œ(์ž์‹ ๋Œ€์‹ )๋กœ ๋ฐฐ์น˜ํ•˜๋Š” ๊ฒƒ์ด ์ œ์•ˆ๋˜์—ˆ์ง€๋งŒ ๋งŽ์€ ์‚ฌ์šฉ ์‚ฌ๋ก€(๋‚ด ๊ฒฝ์šฐ ํฌํ•จ)์—์„œ๋Š” ์ž‘๋™ํ•˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๋งˆ์นจ๋‚ด ReactDOM.unstable_renderSubtreeIntoContainer ๊ฐ€ ์ œ๊ฑฐ ๋  ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค , ๊ณง ์ด ๋ฌธ์ œ์— ๋Œ€ํ•œ ํ•ฉ๋ฆฌ์ ์ธ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์ด ๋‚จ์ง€ ์•Š์„ ๊ฒƒ์ž„์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค...

^ ๋„์™€์ฃผ์„ธ์š” @trueadm -nobi ๋‹น์‹ ์€ ์šฐ๋ฆฌ์˜ ์œ ์ผํ•œ ํฌ๋ง์ž…๋‹ˆ๋‹ค

GitHub์—์„œ ping์„ ์‹คํ–‰ํ•ด๋„ ์ž‘๋™ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค ๐Ÿ˜ž
ํŠธ์œ„ํ„ฐ ๊ณ„์ •์ด ํ™œ์„ฑํ™”๋œ ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ๊ธฐ์—ฌ์ž ์ค‘ ํ•œ ๋ช…์„ ํƒœ๊ทธํ•˜์—ฌ ์ด์— ๋Œ€ํ•ด ํŠธ์œ—ํ•  ์ˆ˜ ์žˆ์„๊นŒ์š”?

์ด ๋ฌธ์ œ์— ๋Œ€ํ•ด ๋‚ด +1์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. Notion์—์„œ๋Š” ํ˜„์žฌ React.createPortal ์ด์ „์˜ ์‚ฌ์šฉ์ž ์ •์˜ ํฌํ„ธ ๊ตฌํ˜„์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์œผ๋ฉฐ ์ปจํ…์ŠคํŠธ ์ œ๊ณต์ž๋ฅผ ์ƒˆ ํŠธ๋ฆฌ์— ์ˆ˜๋™์œผ๋กœ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค. React.createPortal ๋ฅผ ์ฑ„ํƒํ•˜๋ ค๊ณ  ํ–ˆ์ง€๋งŒ ์˜ˆ๊ธฐ์น˜ ์•Š์€ ๋ฒ„๋ธ”๋ง ๋™์ž‘์œผ๋กœ ์ธํ•ด ์ฐจ๋‹จ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

<MenuItem> ๊ตฌ์„ฑ ์š”์†Œ ์™ธ๋ถ€๋กœ <Portal> ๋ฅผ ์ด๋™ํ•˜์—ฌ ํ˜•์ œ๊ฐ€ ๋˜๋„๋ก ํ•˜๋Š” @sebmarkbage ์˜ ์ œ์•ˆ์€ ๋‹จ์ผ ์ค‘์ฒฉ ์ˆ˜์ค€์— ๋Œ€ํ•œ ๋ฌธ์ œ๋งŒ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค. ํ•˜์œ„ ๋ฉ”๋‰ด๋ฅผ ํฌํ„ธ ์•„์›ƒํ•˜๋Š” ์—ฌ๋Ÿฌ ์ค‘์ฒฉ(์˜ˆ:) ๋ฉ”๋‰ด ํ•ญ๋ชฉ์ด ์žˆ๋Š” ๊ฒฝ์šฐ ๋ฌธ์ œ๊ฐ€ ๋‚จ์•„ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ๋ฌธ์ œ๋Š” ์ž๋™์œผ๋กœ ์˜ค๋ž˜๋œ ๊ฒƒ์œผ๋กœ ํ‘œ์‹œ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ฌธ์ œ๊ฐ€ ์—ฌ์ „ํžˆ ์˜ํ–ฅ์„ ๋ฏธ์น˜๋Š” ๊ฒฝ์šฐ ์˜๊ฒฌ์„ ๋‚จ๊ฒจ์ฃผ์„ธ์š” (์˜ˆ: "bump"). ๊ณ„์† ์—ด์–ด

์ถฉ๋Œ.

Dan์€ ๊ด€๋ จ ๋ฌธ์ œ์— ๋Œ€ํ•ด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋Œ“๊ธ€ ์„ ๋‚จ๊ฒผ

@mogelbrod ํ˜„์žฌ ์ถ”๊ฐ€ํ•  ๊ฒƒ์ด ์—†์ง€๋งŒ ๊ธฐ์กด ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ํ•˜๋Š” ๊ฒฝ์šฐ ์ด์™€ ๊ฐ™์€ ๊ฒƒ( #11387 (comment) )์ด ํ•ฉ๋ฆฌ์ ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค.

๊ฐ™์€ ๋ฌธ์ œ์— ๋Œ€ํ•œ Dan์˜ ํ›„์† ์กฐ์น˜ :

ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ์ปจํ…์ŠคํŠธ๋ฅผ ์ œ๊ณตํ•ด ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฏธ ํ•ด๋‹น ๋„๋ฉ”์ธ ์ง€์‹์„ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฏ€๋กœ ๊ฐ€์žฅ ์ข‹์€ ๋‹ค์Œ ๋‹จ๊ณ„๋Š” ์›ํ•˜๋Š” ๋™์ž‘๊ณผ ๊ณ ๋ คํ•œ ๋Œ€์•ˆ์— ๋Œ€ํ•œ RFC๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. https://github.com/reactjs/rfcs. "์ด๊ฒƒ์„ ๋ฐ”๊พธ์ž"๋ผ๋Š” RFC๋Š” ๋„์›€์ด ๋˜์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ข‹์€ RFC๋ฅผ ์ž‘์„ฑํ•˜๋ ค๋ฉด ํ˜„์žฌ ๋™์ž‘์ด ์žˆ๋Š” ์ด์œ ์— ๋Œ€ํ•œ ์ดํ•ด์™€ ๋‹ค๋ฅธ ์‚ฌ๋žŒ์—๊ฒŒ ํšŒ๊ท€ํ•˜์ง€ ์•Š๊ณ  ์‚ฌ์šฉ ์‚ฌ๋ก€์— ๋งž๋Š” ๋ฐฉ์‹์œผ๋กœ ๋ณ€๊ฒฝํ•  ๊ณ„ํš์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿผ์—๋„ ๋ถˆ๊ตฌ ํ•˜๊ณ  unstable_renderSubtreeIntoContainer ๋Š” ์ง€์›๋˜์ง€ ์•Š์œผ๋ฏ€๋กœ ์ด ๋‘ ๊ฐ€์ง€ ๋…ผ์˜๋ฅผ ํ’€์–ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์ „์ฒด API๊ฐ€ ๊ณ ์ •๋˜์–ด ์—…๋ฐ์ดํŠธ๋˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— Context ์ „ํŒŒ๋ฅผ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋…ผ์˜๋œ ํ”Œ๋ž˜๊ทธ ๋˜๋Š” ๋‹ค๋ฅธ ์†”๋ฃจ์…˜์˜ ์ถ”๊ฐ€๋ฅผ ์ œ์•ˆํ•˜๊ธฐ ์œ„ํ•ด React RFC๋ฅผ ํ™•์‹คํžˆ ๊ฒŒ์‹œํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ดˆ์•ˆ ์ž‘์„ฑ์— ํŠนํžˆ ๊ด€์‹ฌ์ด ์žˆ๋‹ค๊ณ  ๋Š๋ผ๋Š” ์‚ฌ๋žŒ์ด ์žˆ์Šต๋‹ˆ๊นŒ(์•„๋งˆ๋„ @justjake , @craigkovatch ๋˜๋Š” @jquense)? ๊ทธ๋ ‡์ง€ ์•Š๋‹ค๋ฉด ๋‚ด๊ฐ€ ๋ฌด์—‡์„ ์ƒ๊ฐํ•ด ๋‚ผ ์ˆ˜ ์žˆ๋Š”์ง€ ๋ณผ ๊ฒƒ์ž…๋‹ˆ๋‹ค!

์ด API๋ฅผ ๋ฐœ์ „์‹œํ‚ค๋Š” ๋ฐ๋Š” ๊ด€์‹ฌ์ด ์žˆ์ง€๋งŒ RFC ์ดˆ์•ˆ์—๋Š” ๊ด€์‹ฌ์ด ์—†์Šต๋‹ˆ๋‹ค. ๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ ์ž‘์—…๋Ÿ‰์ด ๋งŽ๊ณ  ์Šน์ธ๋  ๊ฐ€๋Šฅ์„ฑ์€ ๊ฑฐ์˜ ์—†์Šต๋‹ˆ๋‹ค. ํ•ต์‹ฌ ํŒ€์ด ๋กœ๋“œ๋งต์— ์•„์ง ์—†๋Š” RFC๋ฅผ ์‹ค์ œ๋กœ ๊ณ ๋ คํ•˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

@jquense ์ด๊ฒƒ์ด ์ •ํ™•ํ•˜์ง€ ์•Š๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ, ์ƒˆ๋กœ์šด API๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์€ ํ•ญ์ƒ ๊ต์ฐจ ์ž‘์—…์ด๊ณ  ๊ณ„ํš๋œ ๋‹ค๋ฅธ ๋ชจ๋“  ๊ธฐ๋Šฅ์— ์˜ํ–ฅ์„ ๋ฏธ์น˜๊ธฐ ๋•Œ๋ฌธ์— ๋น„์ „๊ณผ ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” RFC๋ฅผ ๋ณ‘ํ•ฉํ•  ๊ฐ€๋Šฅ์„ฑ์€ ๋‚ฎ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์šฐ๋ฆฌ๊ฐ€ ์ข…์ข… ์ž‘๋™ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์— ๋Œ€ํ•ด ์–ธ๊ธ‰ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์€ ๊ณต์ •ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์šฐ๋ฆฌ๋Š” ๊ทธ๊ฒƒ๋“ค์„ ์ฝ๊ณ , ํŠนํžˆ ์ƒํƒœ๊ณ„๊ฐ€ ๋” ์ „๋ฌธ์ ์ธ ์ฃผ์ œ์— ์ ‘๊ทผํ•  ๋•Œ ์ฝ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด https://github.com/reactjs/rfcs/pull/38 , https://github.com/ reactjs/rfcs/pull/150 , https://github.com/reactjs/rfcs/pull/118 , https://github.com/reactjs/rfcs/pull/109 , https://github.com/reactjs/ rfcs/pull/32 ๋Š” ์šฐ๋ฆฌ๊ฐ€ ๊ทธ๋“ค์— ๋Œ€ํ•ด ๋ช…์‹œ์ ์œผ๋กœ ์–ธ๊ธ‰ํ•˜์ง€ ์•Š์•˜์ง€๋งŒ ๋ชจ๋‘ ์šฐ๋ฆฌ์˜ ์ƒ๊ฐ์— ์˜ํ–ฅ์„ ๋ฏธ์ณค์Šต๋‹ˆ๋‹ค.

๋‹ค์‹œ ๋งํ•ด์„œ, ์šฐ๋ฆฌ๋Š” ๋ถ€๋ถ„์ ์œผ๋กœ ์ปค๋ฎค๋‹ˆํ‹ฐ ์—ฐ๊ตฌ ๋ฉ”์ปค๋‹ˆ์ฆ˜์œผ๋กœ RFC์— ์ ‘๊ทผํ•ฉ๋‹ˆ๋‹ค. ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์ด ์„ฑ๊ฐ€์‹  ์ด์œ ์— ๋Œ€ํ•œ @mogelbrod (https://github.com/facebook/react/issues/16721#issuecomment-674748100)์˜ ์ด ์˜๊ฒฌ์€ RFC์—์„œ ๋ณด๊ณ  ์‹ถ์€ ๋ฐ”๋กœ ๊ทธ ์ข…๋ฅ˜์ž…๋‹ˆ๋‹ค. ๊ธฐ์กด ์†”๋ฃจ์…˜๊ณผ ๊ทธ ๋‹จ์ ์„ ๊ณ ๋ คํ•˜๋Š” ๊ฒƒ์ด ๊ตฌ์ฒด์ ์ธ API ์ œ์•ˆ ์ œ์•ˆ๋ณด๋‹ค ๋” ๊ฐ€์น˜๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@gaearon ๋‚ด ์˜๊ฒฌ์€ ํŒ€์ด ์™ธ๋ถ€ ํ”ผ๋“œ๋ฐฑ์„ ๋“ฃ์ง€ ์•Š๋Š”๋‹ค๋Š” ์ œ์•ˆ์ด ์•„๋‹™๋‹ˆ๋‹ค. ์ž˜ ํ•ด๋‚ด๊ฒ ์Šต๋‹ˆ๋‹ค. ๋‚ด ์˜๊ฒฌ์ด ์ •ํ™•ํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. RFC ์ €์žฅ์†Œ์—์„œ ์‹คํ–‰๋˜๋Š” _process_๋Š” ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค๋กœ๋ถ€ํ„ฐ RFC๋ฅผ ์ˆ˜๋ฝํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์–ด๋–ค RFC๊ฐ€ ๋ณ‘ํ•ฉ๋˜๋Š”์ง€ ๋ณด๋ฉด ์ „์ ์œผ๋กœ ํ•ต์‹ฌ ํŒ€์› ๋˜๋Š” fb ์ง์›์ด๋ฉฐ ๋‹ค๋ฅธ ์‚ฌ๋žŒ์ด ์•„๋‹™๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์„ ๋งŒ๋“œ๋Š” ๊ธฐ๋Šฅ์€ ์ผ๋ฐ˜์ ์œผ๋กœ ์•ฝ๊ฐ„ ๋‹ค๋ฅด๋ฉฐ RFC ํ”„๋กœ์„ธ์Šค์— ์ „ํ˜€ ์ฐธ์—ฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค(์˜ˆ: ๋™ํ˜• ID).

๋‹ค๋ฅธ RFC๋ฅผ ์‚ดํŽด๋ณด๊ณ  ๊ธฐ๋Šฅ ์„ค๊ณ„์— ๊ธฐ์—ฌํ•œ๋‹ค๋Š” ์†Œ์‹์„ ๋“ฃ๊ฒŒ ๋˜์–ด ๋งค์šฐ ๊ธฐ์ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ "์šฐ๋ฆฌ๋Š” RFC์— ๋Œ€ํ•ด ์–ธ๊ธ‰ํ•œ ์ ์ด ์—†์ง€๋งŒ ์™ธ๋ถ€ RFC์˜ ์˜ํ–ฅ์„ ๋ฐ›์•˜์Šต๋‹ˆ๋‹ค." ๋„์ „ํ•˜์„ธ์š”.

๋‹ค์‹œ ๋งํ•ด์„œ, ์šฐ๋ฆฌ๋Š” ๋ถ€๋ถ„์ ์œผ๋กœ ์ปค๋ฎค๋‹ˆํ‹ฐ ์—ฐ๊ตฌ ๋ฉ”์ปค๋‹ˆ์ฆ˜์œผ๋กœ RFC์— ์ ‘๊ทผํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๊ฒƒ์€ ๋งค์šฐ ํ•ฉ๋ฆฌ์ ์ด์ง€๋งŒ RFC repo๊ฐ€ โ€‹โ€‹๋งํ•˜๋Š” _its_ ์ ‘๊ทผ ๋ฐฉ์‹์ด ์•„๋‹ˆ๋ฉฐ ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค์ด ์ผ๋ฐ˜์ ์œผ๋กœ RFC์— ๋Œ€ํ•ด ์ƒ๊ฐํ•˜๋Š” ๋ฐฉ์‹์ด ์•„๋‹™๋‹ˆ๋‹ค. RFC ํ”„๋กœ์„ธ์Šค๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ํŒ€๊ณผ ์ปค๋ฎค๋‹ˆํ‹ฐ ๊ฐ„์˜ ์—ฐ๊ฒฐ์ด์ž ์ปค๋ฎค๋‹ˆ์ผ€์ด์…˜ ์ง€์ ์ด๋ฉฐ ๊ธฐ๋Šฅ ๊ณ ๋ ค ๋ฐ ํ”„๋กœ์„ธ์Šค ์ธก๋ฉด์—์„œ ๊ณตํ‰ํ•œ ๊ฒฝ์Ÿ์˜ ์žฅ์ž…๋‹ˆ๋‹ค.

์ปค๋ฎค๋‹ˆํ‹ฐ ๊ฑฐ๋ฒ„๋„Œ์Šค์— ๋Œ€ํ•œ ๋” ํฐ ์š”์ ์€ ์ œ์ณ๋‘๊ณ . ์‚ฌ๋žŒ๋“ค์—๊ฒŒ ์ž์„ธํ•œ ์ œ์•ˆ์„ ์ž‘์„ฑํ•˜๋Š” ๋ฐ ์‹œ๊ฐ„์„ ํ• ์• ํ•˜๊ณ  ๋ฐ˜์‘ ํŒ€์˜ ์นจ๋ฌต์„ ๋งŒ๋‚˜๋Š” ๋™์•ˆ ๋‹ค๋ฅธ ์™ธ๋ถ€ ์ฐธ๊ฐ€์ž์—๊ฒŒ ์ด๋ฅผ ๋ฐฉ์–ดํ•˜๋„๋ก ์š”์ฒญํ•˜๋Š” ๊ฒƒ์€ ๋‚™๋‹ดํ•˜๊ณ  FB๊ฐ€ OSS์— ๋Œ€ํ•œ ์ž์‹ ์˜ ์š”๊ตฌ์—๋งŒ ๊ด€์‹ฌ์„ ๊ฐ–๋Š”๋‹ค๋Š” ์ธ์ƒ์„ ์ ๊ทน์ ์œผ๋กœ ๊ฐ•ํ™”ํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋‹น์‹ ์ด ๊ทธ๋Ÿฐ ์‹์œผ๋กœ ๋Š๋ผ๊ฑฐ๋‚˜ ๋””์ž์ธํ•˜์ง€ ์•Š์„ ๊ฒƒ์ด๋ผ๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ƒ„์ƒˆ๊ฐ€๋‚ฉ๋‹ˆ๋‹ค.

RFC ํ”„๋กœ์„ธ์Šค๊ฐ€ "์—ฌ๊ธฐ์— ์šฐ๋ ค ์‚ฌํ•ญ๊ณผ ์‚ฌ์šฉ ์‚ฌ๋ก€๋ฅผ ์„ค๋ช…ํ•  ์ˆ˜ ์žˆ๋Š” ๊ณณ์ด ์žˆ์œผ๋ฉฐ ์ด ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋Š” ์‹œ์ ์— ๋„๋‹ฌํ•˜๋ฉด ์ฝ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค". ์†”์งํžˆ ์ข‹์€ ์ ‘๊ทผ์ž…๋‹ˆ๋‹ค. ์ปค๋ฎค๋‹ˆํ‹ฐ๊ฐ€ ์ด๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ์„ค๋ช…ํ•˜๋ฉด ์ด์ต์„ ์–ป์„ ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ppl์ด ๋‹ค๋ฅธ RFC ํ”„๋กœ์„ธ์Šค์™€ ๋™์ผํ•œ ์ˆ˜์ค€์˜ ์ฐธ์—ฌ ๋ฐ ์ฐธ์—ฌ๋ฅผ ๊ฐ€์ •ํ•œ ๋‹ค์Œ ์ œ๋Œ€๋กœ ์‹คํ–‰๋˜์ง€ ์•Š์„ ๋•Œ ์ ๊ทน์ ์œผ๋กœ ๋‚™๋‹ดํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ๊ธฐ์—ฌ์ž๋ณด๋‹ค ์•ฝ๊ฐ„ ๋” ํ†ต์ฐฐ๋ ฅ์ด ์žˆ์–ด๋„ ํ™•์‹คํžˆ ๊ทธ๋Ÿฐ ์ธ์ƒ์„ ๋ฐ›์•˜์Šต๋‹ˆ๋‹ค.

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

์ถฉ๋ถ„ํžˆ ๊ณตํ‰ํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ RFC์— ๋Œ€ํ•œ ๋ฉ”ํƒ€๋ฅผ ์–ป๊ธฐ์— ์ ํ•ฉํ•œ ์žฅ์†Œ๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. :)

@gaearon ์ด๊ฒƒ์€ ํ˜„์žฌ React์—์„œ ์—ด๋ฆฐ 6๋ฒˆ์งธ๋กœ ๊ฐ€์žฅ ๋งŽ์ด

์ด ๋ฌธ์ œ์— ๋Œ€ํ•ด ์–ธ๊ธ‰ํ•œ ๊ฒƒ์„ ์œ ๊ฐ์Šค๋Ÿฝ๊ฒŒ ์ƒ๊ฐํ•˜๋ฉฐ ์ปค๋ฎค๋‹ˆํ‹ฐ RFC์— ๋Œ€ํ•œ ์ œ์•ˆ์„ ์ฒ ํšŒํ•ฉ๋‹ˆ๋‹ค. ์•„๋งˆ๋„ ๋‚˜์œ ์ƒ๊ฐ์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋‚˜๋Š” ์ด ๋ฌธ์ œ๊ฐ€ ๋งค์šฐ ๊ฐ์ •์ ์ด๋ฉฐ ์ธ๊ฐ„์œผ๋กœ์„œ ๊ฐœ์ธ์ ์œผ๋กœ ๊ทธ๊ฒƒ์— ๊ด€์—ฌํ•˜๋Š” ๊ฒƒ์ด ์–ด๋ ต๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ฒŒ ๋˜์—ˆ๋‹ค๊ณ  ๋ง๋ถ™์ด๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. ๋น„๋ก ๊ทธ๊ฒƒ์ด ์ค‘์š”ํ•˜๊ณ  ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์ด ๊ทธ๊ฒƒ์— ๋Œ€ํ•ด ๊ฐ•ํ•˜๊ฒŒ ๋Š๋‚€๋‹ค๋Š” ๊ฒƒ์„ ์ดํ•ดํ•˜์ง€๋งŒ ๋ง์ž…๋‹ˆ๋‹ค.

์ด ์Šค๋ ˆ๋“œ์˜ ์ƒํƒœ์— ๋Œ€ํ•ด ๊ฐ„๋‹จํžˆ ๋‹ต๋ณ€ํ•ด ๋“œ๋ฆฌ๊ฒ ์Šต๋‹ˆ๋‹ค.

๋จผ์ €, ์ด ์Šค๋ ˆ๋“œ์—์„œ ํ›„์† ์กฐ์น˜๋ฅผ ๊ณ„์†ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์— ๋Œ€ํ•ด ๋Œ“๊ธ€์„ ๋‹ฌ๊ณ  ์†์ƒํ•ด ํ•˜์…จ๋˜ ๋ถ„๋“ค๊ป˜ ์ฃ„์†กํ•˜๋‹ค๋Š” ๋ง์”€์„ ๋“œ๋ฆฌ๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ์™ธ๋ถ€์—์„œ ์ด ๋ฌธ์ œ๋ฅผ ์ฝ์—ˆ๋‹ค๋ฉด React ํŒ€์ด ์‹ค์ˆ˜๋ฅผ ์ €์งˆ๋ €๊ณ , ์ธ์ •ํ•˜๋ ค ํ•˜์ง€ ์•Š์•˜์œผ๋ฉฐ, ๊ฐ„๋‹จํ•œ ํ•ด๊ฒฐ์ฑ…์— ๊ธฐ๊บผ์ด ์•‰์„ ์˜ํ–ฅ์ด ์žˆ๋‹ค๋Š” ์ธ์ƒ์„ ๋ฐ›์•˜์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ ๊ฑฐ์•ผ!") 2๋…„ ๋„˜๊ฒŒ ์ปค๋ฎค๋‹ˆํ‹ฐ๋ฅผ ๋Œ๋ณด์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋‹น์‹ ์ด ์–ด๋–ป๊ฒŒ ์ด๋Ÿฐ ๊ฒฐ๋ก ์— ๋„๋‹ฌํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์ถฉ๋ถ„ํžˆ ์ดํ•ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ์ด ๋ฌธ์ œ๊ฐ€ ๋†’์€ ์ง€์ง€๋ฅผ ๋ฐ›์•˜๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์ด ์Šค๋ ˆ๋“œ์—์„œ ์—ฌ๋Ÿฌ ๋ฒˆ ์ œ๊ธฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. React ํŒ€์ด ์ด๊ฒƒ์ด ํฐ ๋ฌธ์ œ๋ผ๋Š” ๊ฒƒ์„ ์•Œ์•˜๋‹ค๋ฉด ๋” ๋นจ๋ฆฌ ํ•ด๊ฒฐํ–ˆ์„ ๊ฒƒ์ด๋ผ๋Š” ๊ด€์ ์—์„œ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ ๋Š” ์ด๊ฒƒ์ด ๊ณจ์นซ๊ฑฐ๋ฆฌ

์ด ๋ฌธ์ œ์—๋Š” ๊ธด๊ธ‰ํžˆ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•˜๋Š” ๋ณด์•ˆ ์ทจ์•ฝ์ ์ด๋‚˜ ์ถฉ๋Œ๊ณผ ๋‹ฌ๋ฆฌ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” wokaround๊ฐ€ ์ž‘๋™ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค(๊ทธ๋Ÿฌ๋‚˜ ์ด์ƒ์ ์ด์ง€๋Š” ์•Š๊ณ  ์„ฑ๊ฐ€์‹ค ์ˆ˜ ์žˆ์Œ). ๊ทธ ์ค‘ ์ผ๋ถ€๋Š” ํŠนํžˆ React 16 ์ด์ „์— ์ž‘์„ฑ๋œ ์ฝ”๋“œ ์ฃผ๋ณ€์—์„œ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์ด ๋ฌธ์ œ๊ฐ€ ์˜์‹ฌํ•  ์—ฌ์ง€ ์—†์ด ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์—๊ฒŒ ์‹ค๋ง์Šค๋Ÿฌ์› ์ง€๋งŒ ๋™์˜ํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์ด ์žˆ์ง€๋งŒ ๊ตฌ์ฒด์ ์ธ ์‹œ๊ฐ„ ๋‚ด์— ๋Œ€์‘ํ•ด์•ผ ํ•˜๋Š” ์ถฉ๋Œ์ด๋‚˜ ๋ณด์•ˆ ๋ฌธ์ œ์™€๋Š” ์—ฌ์ „ํžˆ ๋‹ค๋ฅธ ์ข…๋ฅ˜์˜ ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค.

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

์˜ˆ๋ฅผ ๋“ค์–ด, ํ˜„์žฌ ๋™์ž‘์€ ์šฐ๋ฆฌ๊ฐ€ ๊ฝค ์˜ค๋žซ๋™์•ˆ ์—ฐ๊ตฌํ•ด ์˜จ ์„ ์–ธ์  ํฌ์ปค์Šค ๊ด€๋ฆฌ ์‚ฌ์šฉ ์‚ฌ๋ก€์— ์‹ค์ œ๋กœ ์ •๋ง ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค. ํฌํ„ธ์ž„์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ๋ถ€ํ’ˆ ํŠธ๋ฆฌ์™€ ๊ด€๋ จํ•˜์—ฌ ๋ชจ๋‹ฌ "๋‚ด๋ถ€"์—์„œ ๋ฐœ์ƒํ•˜๋Š” ํฌ์ปค์Šค/๋ธ”๋Ÿฌ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ด ์Šค๋ ˆ๋“œ์—์„œ ์ œ์•ˆ๋œ "๋‹จ์ˆœํ•œ" createPortal(tree, boolean) ์ œ์•ˆ์„ ์ œ๊ณตํ•˜๋Š” ๊ฒฝ์šฐ ํฌํ„ธ ์ž์ฒด์—์„œ ์šฐ๋ฆฌ๊ฐ€ ์›ํ•˜๋Š” ๋™์ž‘์— ๋Œ€ํ•ด "์•Œ ์ˆ˜" ์—†๊ธฐ ๋•Œ๋ฌธ์— ์ด ์‚ฌ์šฉ ์‚ฌ๋ก€๋Š” ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ฐ€๋Šฅํ•œ ์†”๋ฃจ์…˜์„ ํƒ์ƒ‰ํ•˜๋ ค๋ฉด ์ˆ˜์‹ญ ๊ฐ€์ง€ ์‚ฌ์šฉ ์‚ฌ๋ก€๋ฅผ ๊ณ ๋ คํ•ด์•ผ ํ•˜๋ฉฐ ๊ทธ ์ค‘ ์ผ๋ถ€๋Š” ์•„์ง ์™„์ „ํžˆ ์ดํ•ด๋˜์ง€๋„ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์–ด๋Š ์‹œ์ ์—์„œ ๋ฐ˜๋“œ์‹œ ํ•ด์•ผ ํ•˜๋Š” ์ผ์ด์ง€๋งŒ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์—„์ฒญ๋‚œ ์‹œ๊ฐ„์ด ์†Œ์š”๋˜๋ฉฐ ์ง€๊ธˆ๊นŒ์ง€ ์ง‘์ค‘ํ•  ์ˆ˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.

ํŠนํžˆ ์ด๋ฒคํŠธ๋Š” ๊นŒ๋‹ค๋กœ์šด ์˜์—ญ์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์šฐ๋ฆฌ๋Š” ๋ช‡ ๋…„ ๋™์•ˆ์˜ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๋งŽ์€ ๋ณ€๊ฒฝ์„ ๊ฐ€ํ–ˆ์œผ๋ฉฐ ์˜ฌํ•ด๋Š” ์ด๊ฒƒ์ด ํฐ ์ดˆ์ ์ด์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์šฐ๋ฆฌ๋Š” ํ•œ ๋ฒˆ์— ๋„ˆ๋ฌด ๋งŽ์€ ์ผ์„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

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

์ด๊ฒƒ์ด ์‚ฌ๋žŒ๋“ค์ด ๋“ฃ๊ณ  ์‹ถ์–ดํ•˜๋Š” ๋Œ€๋‹ต์ด ์•„๋‹ˆ๋ผ๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ์ง€๋งŒ, ์•„๋ฌด ๋Œ€๋‹ต๋„ ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ๋ณด๋‹ค๋Š” ๋‚˜์•˜์œผ๋ฉด ํ•ฉ๋‹ˆ๋‹ค.

์–ธ๊ธ‰ํ•  ๊ฐ€์น˜๊ฐ€ ์žˆ๋Š” ๋˜ ๋‹ค๋ฅธ ์‚ฌํ•ญ์€ ์ด ์Šค๋ ˆ๋“œ์— ์„ค๋ช…๋œ ์ผ๋ถ€ ๋ฌธ์ œ์ ์ด ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์œผ๋กœ ํ•ด๊ฒฐ๋˜์—ˆ์„ ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด:

ํŠนํžˆ: ํ•ฉ์„ฑ ํฌ์ปค์Šค ์ด๋ฒคํŠธ์—์„œ stopPropagation์„ ํ˜ธ์ถœํ•˜์—ฌ ํฌํ„ธ ๋ฐ–์œผ๋กœ ๋ฒ„๋ธ”๋ง๋˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜๋ฉด stopPropagation์ด #document์— ์žˆ๋Š” React์˜ ์บก์ฒ˜๋œ ํ•ธ๋“ค๋Ÿฌ์— ์žˆ๋Š” ๋„ค์ดํ‹ฐ๋ธŒ ํฌ์ปค์Šค ์ด๋ฒคํŠธ์—์„œ๋„ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.

React๋Š” ๋” ์ด์ƒ ๋ฒ„๋ธ”๋ง์„ ์—๋ฎฌ๋ ˆ์ดํŠธํ•˜๊ธฐ ์œ„ํ•ด ์บก์ฒ˜ ๋‹จ๊ณ„๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋ฉฐ ๋” ์ด์ƒ ๋ฌธ์„œ์˜ ์ด๋ฒคํŠธ๋ฅผ ์ˆ˜์‹ ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ขŒ์ ˆ๊ฐ์„ ๋ฌด์‹œํ•˜์ง€ ์•Š๊ณ  ๋‹ค๋ฅธ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์— ๋น„์ถ”์–ด ์ง€๊ธˆ๊นŒ์ง€ ๊ฒŒ์‹œ ๋œ ๋ชจ๋“  ๊ฒƒ์„ ์žฌํ‰๊ฐ€ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

๊ธฐ๋ณธ ์ด๋ฒคํŠธ๋Š” ์—ฌ์ „ํžˆ ๊ฑฐํ’ˆ์ด ์ผ๊ณ  React ์ฝ”๋“œ๋Š” ๋Œ€๋ถ€๋ถ„ jQuery ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋‚ด๋ถ€์—์„œ ํ˜ธ์ŠคํŒ…๋˜๊ธฐ ๋•Œ๋ฌธ์— ์ „์—ญ jQuery keyDown ํ•ธ๋“ค๋Ÿฌ๋Š”

์—ฌ์ „ํžˆ ์ด๋ฒคํŠธ๋ฅผ ๋ฐ›์Šต๋‹ˆ๋‹ค.

์œ ์‚ฌํ•˜๊ฒŒ, React 17์€ ๋ฃจํŠธ์™€ ํฌํ„ธ ์ปจํ…Œ์ด๋„ˆ์— ์ด๋ฒคํŠธ๋ฅผ ์ฒจ๋ถ€ํ•  ๊ฒƒ์ด๋ฏ€๋กœ(์‹ค์ œ๋กœ ๊ทธ ์‹œ์ ์—์„œ ๊ธฐ๋ณธ ์ „ํŒŒ๋ฅผ ์ค‘์ง€) ์ €๋„ ํ•ด๊ฒฐ๋  ๊ฒƒ์œผ๋กœ ๊ธฐ๋Œ€ํ•ฉ๋‹ˆ๋‹ค.

renderSubtreeIntoContainer ์— ๋Œ€ํ•œ ํฌ์ธํŠธ๊ฐ€ ์ œ๊ฑฐ๋ฉ๋‹ˆ๋‹ค. ๋ง ๊ทธ๋Œ€๋กœ ReactDOM.render ๊ณผ์˜ ์œ ์ผํ•œ ์ฐจ์ด์ ์€ Legacy Context๋ฅผ ์ „ํŒŒํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. renderSubtreeIntoContainer ํฌํ•จํ•˜์ง€ ์•Š๋Š” ๋ฆด๋ฆฌ์Šค๋Š” Legacy Context๋„ ํฌํ•จํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ReactDOM.render ๋Š” 100% ๋™์ผํ•œ ๋Œ€์•ˆ์œผ๋กœ ๋‚จ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ฌผ๋ก  ์ด๊ฒƒ์€ ๋” ๊ด‘๋ฒ”์œ„ํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜์ง€ ๋ชปํ•˜์ง€๋งŒ ํŠนํžˆ renderSubtree ๋Œ€ํ•œ ์šฐ๋ ค๋Š” ๋‹ค์†Œ ์ž˜๋ชป๋œ ์œ„์น˜์— ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

@gaearon

renderSubtreeIntoContainer ์— ๋Œ€ํ•œ ํฌ์ธํŠธ๊ฐ€ ์ œ๊ฑฐ๋ฉ๋‹ˆ๋‹ค. ๋ง ๊ทธ๋Œ€๋กœ ReactDOM.render ๊ณผ์˜ ์œ ์ผํ•œ ์ฐจ์ด์ ์€ Legacy Context๋ฅผ ์ „ํŒŒํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. renderSubtreeIntoContainer ํฌํ•จํ•˜์ง€ ์•Š๋Š” ๋ฆด๋ฆฌ์Šค๋Š” Legacy Context๋„ ํฌํ•จํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ReactDOM.render ๋Š” 100% ๋™์ผํ•œ ๋Œ€์•ˆ์œผ๋กœ ๋‚จ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ฌผ๋ก  ์ด๊ฒƒ์€ ๋” ๊ด‘๋ฒ”์œ„ํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜์ง€ ๋ชปํ•˜์ง€๋งŒ ํŠนํžˆ renderSubtree ๋Œ€ํ•œ ์šฐ๋ ค๋Š” ๋‹ค์†Œ ์ž˜๋ชป๋œ ์œ„์น˜์— ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

์ด์ œ ์–ธ๊ธ‰ํ•˜์…จ์œผ๋‹ˆ ์•„๋ž˜ ์ฝ”๋“œ๊ฐ€ ์ด๋ฒคํŠธ ๋ฒ„๋ธ”๋ง ์—†์ด React Portal์— ๋Œ€ํ•ด ์œ ํšจํ•˜๊ณ  ์•ˆ์ „ํ•œ ๊ตฌํ˜„์ด ๋  ์ˆ˜ ์žˆ์„์ง€ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค.

function Portal({ children }) {
  const containerRef = React.useRef();

  React.useEffect(() => {
    const container = document.createElement("div");
    containerRef.current = container;
    document.body.appendChild(container);
    return () => {
      ReactDOM.unmountComponentAtNode(container);
      document.body.removeChild(container);
    };
  }, []);

  React.useEffect(() => {
    ReactDOM.render(children, containerRef.current);
  }, [children]);

  return null;
}

์ผ๋ถ€ ํ…Œ์ŠคํŠธ๊ฐ€ ํฌํ•จ๋œ CodeSandbox: https://codesandbox.io/s/react-portal-with-reactdom-render-m22dj?file=/src/App.js

Modern Context๋ฅผ ํ†ต๊ณผํ•˜์ง€ ๋ชปํ•˜๋Š” ๋ฌธ์ œ๊ฐ€ ์—ฌ์ „ํžˆ ์žˆ์ง€๋งŒ ์ด๊ฒƒ์€ ์ƒˆ๋กœ์šด ๋ฌธ์ œ๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค( renderSubtree ๋„ ์˜ํ–ฅ์„ ๋ฐ›์Šต๋‹ˆ๋‹ค). ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์€ ์—ฌ๋Ÿฌ ์ปจํ…์ŠคํŠธ ๊ณต๊ธ‰์ž๋กœ ํŠธ๋ฆฌ๋ฅผ ๋‘˜๋Ÿฌ์‹ธ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ „๋ฐ˜์ ์œผ๋กœ ํŠธ๋ฆฌ๋ฅผ ์ค‘์ฒฉํ•˜๋Š” ๊ฒƒ์€ ์ด์ƒ์ ์ด์ง€ ์•Š์œผ๋ฏ€๋กœ ๊ธฐ์กด ๊ธฐ์กด ์ฝ”๋“œ ์‹œ๋‚˜๋ฆฌ์˜ค ์ด์™ธ์˜ ๋‹ค๋ฅธ ํŒจํ„ด์—์„œ๋Š” ์ด ํŒจํ„ด์œผ๋กœ ์ „ํ™˜ํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋‹ค์‹œ ํ•œ๋ฒˆ @gaearon์„ ์จ์ฃผ์…”์„œ ์ •๋ง ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!

๊ณ ์žฅ๋‚œ ์ผ€์ด์Šค + ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•(React v17์šฉ์œผ๋กœ ์—…๋ฐ์ดํŠธ๋จ) ๋ชฉ๋ก์„ ์ง‘๊ณ„ํ•˜๋Š” ๊ฒƒ์ด ํ•ต์‹ฌ ํŒ€ ์™ธ๋ถ€์˜ ๋ˆ„๊ตฐ๊ฐ€์—๊ฒŒ ๊ฐ€์žฅ ์ƒ์‚ฐ์ ์ธ ์ผ์ธ ๊ฒƒ์ฒ˜๋Ÿผ ๋“ค๋ฆฝ๋‹ˆ๋‹ค(ํ‹€๋ฆฐ ๊ฒฝ์šฐ ์ˆ˜์ •ํ•ด ์ฃผ์„ธ์š”!).

๋‚˜๋Š” ์•ž์œผ๋กœ ๋ช‡ ์ฃผ ๋™์•ˆ ๋Šช์— ๋น ์กŒ์ง€๋งŒ ์ตœ๋Œ€ํ•œ ๋นจ๋ฆฌ ํ•˜๋Š” ๊ฒƒ์„ ๋ชฉํ‘œ๋กœ ์‚ผ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ์‚ฌ๋žŒ์ด ๋” ์ผ์ฐ ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๊ฑฐ๋‚˜ ์Šค๋‹ˆํŽซ( @diegohaz๊ฐ€ ๋ฐฉ๊ธˆ ํ•œ ๊ฒƒ์ฒ˜๋Ÿผ)์œผ๋กœ ์ฐจ์ž„ํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ๊ทธ๊ฒƒ์€ ๊ต‰์žฅํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค!

์‚ฌ๋ก€ ๋ชฉ๋ก์„ ์ง‘๊ณ„ํ•˜๋Š” ๊ฒƒ์€ ํ™•์‹คํžˆ ์œ ์šฉํ•  ๊ฒƒ์ด์ง€๋งŒ, ๊นจ์ง„ ์‚ฌ๋ก€๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ํ˜„์žฌ ํ–‰๋™์ด ์˜๋ฏธ๊ฐ€ ์žˆ๋Š” ์‚ฌ๋ก€๋„ ํฌํ•จํ•ด์•ผ ํ•œ๋‹ค๊ณ  ๋งํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.

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

์‚ฌ๋ก€ ๋ชฉ๋ก์„ ์ง‘๊ณ„ํ•˜๋Š” ๊ฒƒ์€ ํ™•์‹คํžˆ ์œ ์šฉํ•  ๊ฒƒ์ด์ง€๋งŒ, ๊นจ์ง„ ์‚ฌ๋ก€๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ํ˜„์žฌ ํ–‰๋™์ด ์˜๋ฏธ๊ฐ€ ์žˆ๋Š” ์‚ฌ๋ก€๋„ ํฌํ•จํ•ด์•ผ ํ•œ๋‹ค๊ณ  ๋งํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.

๋ˆ„๊ตฐ๊ฐ€ ์ €์—๊ฒŒ ์˜์กดํ•˜๋Š” ์˜คํ”ˆ ์†Œ์Šค ์ฝ”๋“œ/์ถ”์ถœ๋œ ์ฝ”๋“œ๋ฅผ ์•Œ๋ ค์ค„ ์ˆ˜ ์žˆ๋‹ค๋ฉด ์ด๊ฒƒ๋“ค์„ ํฌํ•จํ•˜๊ฒŒ ๋˜์–ด ๊ธฐ์ฉ๋‹ˆ๋‹ค! ์ด์ „์— ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด ํ˜„์žฌ ํ–‰๋™์— ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š” ์‚ฌ๋žŒ๋“ค๋งŒ ์ด ๋ฌธ์ œ์— ๊ด€๋ จ๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ฐพ๊ธฐ๊ฐ€ ์•ฝ๊ฐ„ ์–ด๋ ต์Šต๋‹ˆ๋‹ค ๐Ÿ˜…

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

์—ผ๋‘์— ๋‘๊ณ  ์žˆ๋Š” ํŠน์ • ๊ณต๊ฐ„์ด ์žˆ๊ฑฐ๋‚˜ ์‚ฌ๋ก€๋‹น ํ•˜๋‚˜์˜ ์ฝ”๋“œ์ƒŒ๋“œ๋ฐ•์Šค (๋˜๋Š” jsfiddle ๋“ฑ)๋ฅผ ๊ณต์œ ํ•˜๋Š” ๊ฒƒ์ด ์Šคํƒ€ํ„ฐ๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๊นŒ? ๋ช‡ ๊ฐ€์ง€ ์‚ฌ๋ก€๋ฅผ ์ˆ˜์ง‘ํ•˜๋ฉด ๋ชจ๋‘ ์ปดํŒŒ์ผ์„ ์‹œ๋„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

https://github.com/facebook/react/issues/19637 ์—์„œ ์Šค๋ ˆ๋“œ๋ฅผ ์‹œ์ž‘ํ–ˆ์Šต๋‹ˆ๋‹ค

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰