æ©èœããªã¯ãšã¹ãããã°ãå ±åããŸããïŒ
æ©èœã ãã§ãªãããââã°ãåå ã§æ°ããAPIãå€ãunstable_rendersubtreeintocontainer
å£ããŠããŸã
çŸåšã®åäœã¯äœã§ããïŒ
ããŒã¿ã«ãããã®ReactããªãŒã®ç¥å
ãžã®ãã¹ãŠã®ã€ãã³ãã®äŒæãåæ¢ããããšã¯ã§ããŸããã ã¢ãŒãã«/ããããªãŒããŒãå®å
šã«å£ããã¬ã€ã€ãŒã¡ã«ããºã ã ããšãã°ãããããããŠã³ãã¿ã³ããããŸãã ãããã¯ãªãã¯ãããšãã¯ãªãã¯ãããšããããªãŒããŒãéããŸãã ãŸããåããã¿ã³ãã¯ãªãã¯ãããšãã«ãã®ããããªãŒããŒãéããããšæããŸãã createPortalã䜿çšããŠãããããªãŒããŒã®å
åŽãã¯ãªãã¯ãããšããã¿ã³ãã¯ãªãã¯ããŠéããŸãã ãã®åçŽãªã±ãŒã¹ã§ã¯ãstopPropagationã䜿çšã§ããŸãã ãããããã®ãããªã±ãŒã¹ã¯ãããããããããããã¹ãŠã«stopPropagationã䜿çšããå¿
èŠããããŸãã ãŸãããã¹ãŠã®ã€ãã³ããåæ¢ããããšã¯ã§ããŸããã
æåŸ
ãããåäœã¯äœã§ããïŒ
createPortalã«ã¯ããã¹ãŠã®ã€ãã³ããæåã§åæ¢ããã«ãReactããªãŒãä»ããåæã€ãã³ãã®äŒæãåæ¢ãããªãã·ã§ã³ãå¿
èŠã§ãã ã©ãæããŸããïŒ
ãŸããmouseOver / Leaveã®äŒæã¯ãŸã£ããäºæ³å€ã«èŠããŸãã
ããŒã¿ã«ããã¿ã³ã®å€ã«ç§»åã§ããŸããïŒ
äŸãã°
return [
<div key="main">
<p>Hello! This is first step.</p>
<Button key="button" />
</div>,
<Portal key="portal" />
];
ãã®åŸããã¿ã³ãä»ããŠããã«ããŸããã
ããã¯ç§ã®æåã®èãã§ããããïŒïŒãã®ãããªã³ã³ããŒãã³ãã³ã³ããã«mouseEnterãã³ãã©ããããšæ³åããŠãã ããã
unstable_rendersubtreeintocontainer
ã§ã¯ã ButtonWithPopover
ã³ã³ããŒãã³ãã®ã€ãã³ããšã¯äœã®é¢ä¿ããããŸãããmouseEnterã¯ãããŠã¹ãå®éã«div
ãšãã¿ã³DOMèŠçŽ ã«å
¥ã£ããšãã«æ©èœããããŠã¹ãããããªãŒããŒã®äžã«ãããšãã«èµ·åãããŸããã ããŒã¿ã«ã§ã¯ãããããªãŒããŒã®äžã«ããŠã¹ã眮ããšã€ãã³ããçºçããŸããå®éã«ã¯ãçŸæç¹ã§ã¯div
ãè¶
ããŠããŸããã ã ãããç§ã¯äŒæãåæ¢ããå¿
èŠããããŸãã ButtonWithPopover
ã³ã³ããŒãã³ãã§å®è¡ãããšãããŠã¹ããã¿ã³ã®äžã«ãããšãã«ã€ãã³ãã®çºçãäžæãããŸãã ããããªãŒããŒã§ãããè¡ãããã®ã¢ããªã±ãŒã·ã§ã³ã«äžè¬çãªããããªãŒããŒã³ã³ããŒãã³ãã䜿çšããŠããå Žåãä»ã®ã¢ããªããŒãã®ããžãã¯ãå£ãããšããããŸãã
ReactããªãŒããããªã³ã°ããç®çãããããããŸããã ããŒã¿ã«ã³ã³ããŒãã³ãããã®ã€ãã³ããå¿
èŠãªå ŽåâåçŽã«å°éå
·ãä»ããŠãã³ãã©ãŒãæž¡ãããšãã§ããŸãã ç§ãã¡ã¯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å®è£ ã®ããã«ã€ãã³ããåãåãããšãæåŸ ããŠããŸãã ç§ã®äŸã§ã¯ãã€ãã³ãã¯ããŒã¿ã«ãä»ããŠäŒæããããã®DOMã®èŠªãåé¿ããŸããããã¯ããã°ãšèŠãªãããšãã§ããŸãã
人ã ã¯è°è«ã«æè¬ããŸãããããç§ã¯äœãããã°ã§ãããã©ãããè°è«ããããšã¯ããã»ã©åœ¹ã«ç«ããªããšæããŸãã 代ããã«ãçŸåšã®åäœã§ã¯æºããããªããŠãŒã¹ã±ãŒã¹ãšäŸã«ã€ããŠè°è«ããæ¹ãçç£çã§ãããããçŸåšã®æ¹æ³ãå°æ¥ã®æåã®æ¹æ³ã§ãããã©ãããããããç解ã§ããŸãã
äžè¬ã«ãAPIã§ããŸããŸãªãŠãŒã¹ã±ãŒã¹ãåŠçããä»ã®ãŠãŒã¹ã±ãŒã¹ãé床ã«å¶éããªãããã«ããŸãã ã³ã¢ããŒã ã«ã€ããŠè©±ãããšã¯ã§ããŸããããæ§æå¯èœã«ããããšã¯ãããã解決çã§ã¯ãªããšæããŸãã äžè¬ã«ãReactã¯ãæ§æå¯èœãªAPIãããäžè²«ããAPIã䜿çšããŸãã
ãŸãããã®åäœãDOMã®åäœæ¹æ³ã§ã¯ãªãããšãç解ããŠããŸãããããèªäœããã®ããã«ãã¹ãã§ã¯ãªããšèšãã®ã«ååãªçç±ã§ã¯ãªããšæããŸãã å€ãã®react-domã®åäœã¯ãDOMã®åäœãšã¯ç°ãªããŸããã€ãã³ãã¯ããã€ãã£ãããŒãžã§ã³ãšã¯ãã§ã«ç°ãªãå ŽåããããŸãã ããšãã°ã onChange
ã¯ããã€ãã£ãã®å€æŽã€ãã³ããšã¯ãŸã£ããç°ãªããDOMãšã¯ç°ãªãããã¹ãŠã®åå¿ã€ãã³ãã¯ã¿ã€ãã«é¢ä¿ãªãããã«ããŸãã
代ããã«ãçŸåšã®åäœã§ã¯æºããããªããŠãŒã¹ã±ãŒã¹ãšäŸã«ã€ããŠè©±ãåãæ¹ãçç£çã§ã
React16ãžã®ç§»è¡ã§å£ãã2ã€ã®äŸã次ã«ç€ºããŸãã
ãŸãããã¿ã³ã§èµ·åãããã©ãã°å¯èœãªãã€ã¢ãã°ããããŸãã ããŒã¿ã«ã®äœ¿çšã«ããã£ã«ã¿ãªã³ã°ãèŠçŽ ãè¿œå ããããšããŸãããããã¯ãä»»æã®ããŠã¹*ããŒ*ã€ãã³ãã§StopPropagationãåŒã³åºããŸãã ãã ãããã©ãã°æ©èœãå®è£ ããããã«ãmousemoveã€ãã³ããããã¥ã¡ã³ãã«ãã€ã³ãã§ããããšã«äŸåããŠããŸããããã¯ããŠãŒã¶ãŒãããŠã¹ãããªãã®é床ã§åãããšãã«ãŒãœã«ããã€ã¢ãã°ã®å¢çãé¢ããå¿ èŠã«ãªããããäžè¬çã§ããããé«ãã¬ãã«ã§ããŠã¹ã®åãããã£ããã£ã§ããããã«ããŸãã ãããã®ã€ãã³ãããã£ã«ã¿ãªã³ã°ãããšããã®æ©èœãæ©èœããªããªããŸãã ãã ããããŒã¿ã«ã§ã¯ãããŠã¹ãšããŒã®ã€ãã³ãããã€ã¢ãã°å ããèµ·åãããã¿ã³ãŸã§ãããªã³ã°ããŠãããããããŸããŸãªèŠèŠå¹æã衚瀺ããããã€ã¢ãã°ãéããããŸãã ããŒã¿ã«ãä»ããŠèµ·åããããã¹ãŠã®ã³ã³ããŒãã³ãã10ã20ã®ã€ãã³ããã³ãã©ãŒããã€ã³ãããŠãã®ã€ãã³ãã®äŒæãåæ¢ããããšãæåŸ ããã®ã¯çŸå®çã§ã¯ãªããšæããŸãã
次ã«ãäžæ¬¡ããŠã¹ãŸãã¯äºæ¬¡ããŠã¹ã®ã¯ãªãã¯ã§èµ·åã§ãããããã¢ããã³ã³ããã¹ãã¡ãã¥ãŒããããŸãã ã©ã€ãã©ãªã®å éšã³ã³ã·ã¥ãŒããŒã®1ã€ã«ã¯ããã®ã¡ãã¥ãŒãèµ·åããèŠçŽ ã«ããŠã¹ãã³ãã©ãŒãã¢ã¿ãããããŠããŸãããã¡ãããã¡ãã¥ãŒã«ã¯ãã¢ã€ãã ã®éžæãåŠçããããã®ã¯ãªãã¯ãã³ãã©ãŒããããŸãã ããŠã¹ããŠã³/ããŠã¹ããŠã³ã€ãã³ããã¡ãã¥ãŒãèµ·åãããã¿ã³ã«æ»ã£ãŠãããªã³ã°ããŠãããããã¡ãã¥ãŒã¯ã¯ãªãã¯ãããã³ã«å衚瀺ãããŸãã
ã³ã¢ããŒã ã«ã€ããŠè©±ãããšã¯ã§ããŸããããæ§æå¯èœã«ããããšã¯ãããã解決çã§ã¯ãªããšæããŸãã äžè¬ã«ãReactã¯ãæ§æå¯èœãªAPIãããäžè²«ããAPIã䜿çšããŸãã
ãã®ç¹å®ã®ã±ãŒã¹ã§ã¯ããã®ç«å Žãåèããããã«ããªãïŒããã³ããŒã ïŒã«ãé¡ãããŸãã ã€ãã³ãã®ãããªã³ã°ã¯ãç¹å®ã®ãŠãŒã¹ã±ãŒã¹ã§ã¯èå³æ·±ããšæããŸãïŒãã ããæã«è² ããªããã®ã¯èããããŸããïŒã ããããããã¯ä»ã®äººã«ãšã£ãŠã¯äžèªç±ã«ãªããšæããŸãããããŠããã¯APIã«é倧ãªççŸããããããŸãã unstable_rendersubtreeintocontainer
ã¯æ±ºããŠã¹ãŒããŒãµããŒããããŠããŸãã
ãŸãããã®åäœãDOMã®åäœæ¹æ³ã§ã¯ãªãããšãç解ããŠããŸãããããèªäœããã®ããã«ãã¹ãã§ã¯ãªããšèšãã®ã«ååãªçç±ã§ã¯ãªããšæããŸãã
ããããæ¥ãŠããã®ã¯ããããŸããããã®å Žåã¯ïŒaïŒåºæ¬çãªåäœã§ãããïŒbïŒçŸåšã¯åé¿çããªãããããDOMããã®ããã«æ©èœããªãããšããã®ã¯åŒ·ãè°ââè«ã ãšæããŸããå®å šã«èª¬åŸåã®ãããã®ã§ã¯ãªãã«ããŠãã
ãããŠæ確ã«ããããã«ïŒããããã°ãšèŠãªããšããç§ã®èŠæ±ã¯ãã»ãšãã©ã®å ŽåãåŸã§ã§ã¯ãªãæ©ãä¿®æ£ã®ããã«åªå ãããããã«ããããã®ãã®ã§ãã
ããŒã¿ã«ã®ç§ã®ã¡ã³ã¿ã«ã¢ãã«ã¯ããããããªãŒå ã®åãå Žæã«ãããã®ããã«åäœããŸãããããªãŒããŒãããŒïŒé衚瀺ããªã©ã®åé¡ãåé¿ããæç»/ã¬ã€ã¢ãŠãç®çã§ã®ã¹ã¯ããŒã«ãåé¿ããããšã§ãã
ããŒã¿ã«ãªãã§ã€ã³ã©ã€ã³ã§çºçããåæ§ã®ããããã¢ããããœãªã¥ãŒã·ã§ã³ã¯å€æ°ãããŸãã ããšãã°ãããé£ã®ããã¯ã¹ãå±éãããã¿ã³ã
äŸãšããŠãGitHubã®ãPickyourreactionããã€ã¢ãã°ãåãäžããŸãã ããã¯ããã¿ã³ã®ããé£ã«divãšããŠå®è£
ãããŠããŸãã ããã§åé¡ãªãåäœããŸãã ãã ããå¥ã®z-indexãå¿
èŠãªå ŽåããŸãã¯ãããã®ã³ã¡ã³ããå«ãoverflow: scroll
é åããæã¡äžããå Žåã¯ãDOMã®äœçœ®ãå€æŽããå¿
èŠããããŸãã ã€ãã³ããããªã³ã°ã®ãããªä»ã®ãã®ãä¿åãããªãéãããã®å€æŽãè¡ãã®ã¯å®å
šã§ã¯ãããŸããã
ããããã¢ããããŸãã¯ããããã¢ãŠããã®äž¡æ¹ã®ã¹ã¿ã€ã«ã¯åæ³ã§ãã ã§ã¯ãã³ã³ããŒãã³ããã¬ã€ã¢ãŠãã®å€åŽã«æµ®ããŠããã®ã§ã¯ãªããã¬ã€ã¢ãŠãå ã§ã€ã³ã©ã€ã³ã«ãªã£ãŠããå Žåãåãåé¡ãã©ã®ããã«è§£æ±ºããŸããïŒ
ç§ã®ããã«åããåé¿çã¯ãããŒã¿ã«ã¬ã³ããªã³ã°ã®çŽäžã§stopPropagation
åŒã³åºãããšã§ãïŒ
return createPortal(
<div onClick={e => e.stopPropagation()}>{this.props.children}</div>,
this.el
)
ããŒã¿ã«ã䜿çšããåäžã®æœè±¡åã³ã³ããŒãã³ããããã®ã§ãããã¯ç§ã«ãšã£ãŠã¯ããŸãæ©èœããŸããããã§ãªãå Žåã¯ããã¹ãŠã®createPortal
åŒã³åºããä¿®æ£ããå¿
èŠããããŸãã
@methylããã¯ãããªãŒã®ãããªã³ã°ããããã¯ããå¿
èŠããããã¹ãŠã®ã€ãã³ããç¥ã£ãŠããããšãåæãšããŠããŸãã ãŸãããã©ãã°å¯èœãªãã€ã¢ãã°ã§èª¬æããå Žåãããã¥ã¡ã³ãã«ããã«ã¢ããããã«ã¯mousemove
ãå¿
èŠã§ãããã¬ã³ããªã³ã°ããªãŒãããã«ã¢ããããå¿
èŠã¯ãããŸããã
ããããã¢ããããŸãã¯ããããã¢ãŠããã®äž¡æ¹ã®ã¹ã¿ã€ã«ã¯åæ³ã§ãã ã§ã¯ãã³ã³ããŒãã³ããã¬ã€ã¢ãŠãã®å€åŽã«æµ®ããŠããã®ã§ã¯ãªããã¬ã€ã¢ãŠãå ã§ã€ã³ã©ã€ã³ã«ãªã£ãŠããå Žåãåãåé¡ãã©ã®ããã«è§£æ±ºããŸããïŒ
@sebmarkbageãã®è³ªåãçã«ããªã£ãŠããã®ã
ããã§ã®åé¡ã®ããã€ãã¯ã2ã€ã®ã¡ãœãããæŠå¿µçã«ç°ãªãããšãããŠãããšãã«renderSubtreeIntoContainer
ãcreatePortal
ã«ç§»æ€ãããŠãããšããããã€ãã®ãŠãŒã¹ã±ãŒã¹ã ãšæããŸãã ããŒã¿ã«ã®æŠå¿µã¯éè² è·ã«ãªã£ãŠãããšæããŸãã
ã¢ãŒãã«ãã€ã¢ãã°ã®å Žåãã¢ãŒãã«ããããéãããã¿ã³ã®åã®ããã«åäœããããšã¯ã»ãšãã©ãããŸããã ããªã¬ãŒã³ã³ããŒãã³ãã¯ã open
ç¶æ
ãå¶åŸ¡ãããããã¬ã³ããªã³ã°ããã ãã§ãã ãããã£ãŠããã¿ã³ã®createPortal
ãããã«é©ããããŒã«ã§ã¯ãªããšèšãã®ã§ã¯ãªããããŒã¿ã«ã®å®è£
ãééã£ãŠãããšèšãã®ã¯ééãã ãšæããŸãã ãã®å Žåãã¢ãŒãã«ã¯ããªã¬ãŒã®åã§ã¯ãªããããããããããã§ãããã®ããã«ã¬ã³ããªã³ã°ããªãã§ãã ããã èãããã解決çã®1ã€ã¯ã renderSubtreeIntoContainer
ã䜿ãç¶ããããšã§ããå¥ã®ãŠãŒã¶ãŒã©ã³ããªãã·ã§ã³ã¯ãã¢ãŒãã«ã®ã¬ã³ããªã³ã°ãåŠçããã¢ããªã«ãŒãã®è¿ãã«ModalProvider
é
眮ããïŒã³ã³ããã¹ããä»ããŠïŒã¬ã³ããªã³ã°ããã¡ãœãããæž¡ãããšã§ããä»»æã®ã¢ãŒãã«èŠçŽ ã¯ã«ãŒãã«å¿
èŠã§ã
renderSubtreeIntoContainer
ã¯ãReact 16ã®render
ãŸãã¯ã©ã€ããµã€ã¯ã«ã¡ãœããã®å
éšããåŒã³åºãããšã¯ã§ããŸãããããã«ããããããŸã§èª¬æããŠããã±ãŒã¹ïŒå®éããããè¡ããšã16ïŒãžã®ç§»è¡ãå®å
šã«å€±æããŸããã ããŒã¿ã«ã¯å
¬åŒã®æšå¥šäºé
ã§ãïŒ https ïŒ//reactjs.org/blog/2017/09/26/react-v16.0.html#breaking -changes
ããŒã¿ã«ã®æŠå¿µãéè² è·ã«ãªã£ãŠããŸã£ãå¯èœæ§ãããããšã«åæããŸãã ãã ããã°ããŒãã«ã³ã³ããŒãã³ããšãã®ã³ã³ããã¹ãã®ãœãªã¥ãŒã·ã§ã³ã奜ããã©ããã¯ããããŸããã ããã¯ãã€ãã³ããããã«ã¹ã«ãŒãããã©ãããæå®ããcreatePortalã®ãã©ã°ã«ãã£ãŠç°¡åã«è§£æ±ºã§ããããã§ãã ããã¯ã16以éãšã®APIã®äºææ§ãç¶æãããªããã€ã³ãã©ã°ã«ãªããŸãã
ããŒã¿ã«ã®ãŠãŒã¹ã±ãŒã¹ãšãã€ãã³ãã®äŒæãåæ¢ãããªãã·ã§ã³ãå¿ èŠãªçç±ãæ確ã«ããããšæããŸãã ManyChatã¢ããªã§ã¯ãããŒã¿ã«ã䜿çšããŠãã¬ã€ã€ãŒããäœæããŠããŸãã ããããªãŒããŒãããããããŠã³ãã¡ãã¥ãŒãã¢ãŒãã«ãªã©ãããã€ãã®ã¿ã€ãã®ã³ã³ããŒãã³ãã§äœ¿çšãããã¢ããªå šäœã®ã¬ã€ã€ãŒã·ã¹ãã ããããŸãã ãã¹ãŠã®ã¬ã€ã€ãŒã¯æ°ããã¬ã€ã€ãŒãå ¬éã§ããŸããããšãã°ãã¡ãã¥ãŒã®2çªç®ã®ã¬ãã«ã®ãã¿ã³ã¯ãä»ã®ãã¿ã³ãããããªãŒããŒãéãããšãã§ããã¢ãŒãã«ãŠã£ã³ããŠãããªã¬ãŒã§ããŸãã ã»ãšãã©ã®å Žåãã¬ã€ã€ãŒã¯ãç¬èªã®ã¿ã¹ã¯ã解決ãã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ããã¥ã¡ã³ãããã®ãã¹ãŠã®ã€ãã³ãã¿ã€ãã®äŒæãåæ¢ããReact16ã«æŽæ°ã§ããããã«ããŸããã
ããã¯ããŒã¿ã«ã«é¢é£ä»ããå¿
èŠããããŸããïŒ ããŒã¿ã«ããµã³ãããã¯ã¹åããã®ã§ã¯ãªããïŒããšãã°ïŒ <React.Sandbox>...</React.Sandbox>
ã ãããã£ãå Žåã¯ã©ããªããŸããïŒ
ããã§ãç§ã«ã¯äžå¿ èŠã«è€éã«æããŸãã ãªãã·ã§ã³ã®ããŒã«ãã©ã°ãcreatePortalã«è¿œå ããŠããããªã³ã°åäœããããã¯ã§ããããã«ããªãã®ã¯ãªãã§ããïŒ
@gaearonããã¯ãç§ãã¡ã®ç¹å®ã®ã¹ã©ã€ã¹ã«ãšã£ãŠã¯ããªãäžå¹žãªç¶æ³ã§ã-ããªããŸãã¯ããªãã«ãšã£ãŠ
ç§ã®çŸåšã®èãã¯ãäž¡æ¹ã®ãŠãŒã¹ã±ãŒã¹ããµããŒãããå¿ èŠããããšããããšã§ãã çŸåšã®èŠªãããµãããªãŒã«æµããã³ã³ããã¹ããå¿ èŠã§ãããããã®ãµãããªãŒãDOMã®èŠ³ç¹ããè«ççãªåãšããŠæ©èœããªãããã«ããå¿ èŠããããŠãŒã¹ã±ãŒã¹ãå®éã«ãããŸãã è€éãªã¢ãŒãã«ãæè¯ã®äŸã§ããã¢ãŒãã«ãŠã£ã³ããŠã®ãã©ãŒã ããã®ã€ãã³ããããªã¬ãŒãã¿ã³ãŸã§äŒæããããšã¯ã»ãšãã©ãããŸããããã³ã³ããã¹ãïŒi18nãããŒããªã©ïŒãæž¡ãå¿ èŠããããŸãã
ãã®ãŠãŒã¹ã±ãŒã¹ã¯ãã€ãã³ãã®äŒæãäœã«ã圱é¿ãäžããªãããã«createPortal
ãä»ããŠã¬ã³ããªã³ã°ããããã¢ããªã«ãŒãã«è¿ãModalProviderã§ã»ãšãã©è§£æ±ºã§ãããšèšããŸãããããã¯åé¿çã®ããã«æãå§ããŸããããŸãèšèšãããã¢ãŒããã¯ãã£ã ãŸããã©ã€ãã©ãªãæäŸããã¢ãŒãã«ã¯ãèªå·±å®çµåã§ã¯ãªããªã£ãããããŠãŒã¶ãŒã«ãšã£ãŠããç
©ããããã®ã«ãªããŸãã
APIã®èŠ³ç¹ããè¿œå ããŸãã createPortal
ãäž¡æ¹ãå®è¡ããå¿
èŠã¯ãªããšæããŸããã¢ãŒãã«ã±ãŒã¹ã§ã¯ãæ確ãªããªãŒã«ããªãè¿ãããã ReactDOM.render
ïŒå€ãskoolïŒã䜿çšããããšèããŠããŸãããã®ã³ã³ããã¹ãã®äŒæã¯ãã°ãã°å¿
èŠã§ã
@ kib357ãæçš¿ããåé¿çã䜿çšããçµæãå€éšã¢ããªã±ãŒã·ã§ã³ã®ãã©ãŒã«ã¹ç®¡çã³ãŒãã®èšºæãéåžžã«é£ãããã°ãä¿®æ£ãã
å
·äœçã«ã¯ãåæãã©ãŒã«ã¹ã€ãã³ãã§stopPropagationãåŒã³åºããŠãããŒã¿ã«ããã®ãããªã³ã°ãé²æ¢ãããšãïŒdocumentã®Reactã®ãã£ããã£ããããã³ãã©ãŒã®ãã€ãã£ããã©ãŒã«ã¹ã€ãã³ãã§ãstopPropagationãåŒã³åºãããŸããã€ãŸãã <body>
å¥ã®ãã£ããã£ããããã³ãã©ãŒã«ã¯å°éããŸãã
ããŒã¿ã«ã§ã®æ°ãããããªã³ã°åäœã¯ãç§ã«ãšã£ãŠã¯å°æ°æŽŸã®ã±ãŒã¹ã®ããã«æããŸãã ãã®æèŠãçå®ããç§ãã¡ã¯ãã®åé¡ã«ã€ããŠããããã®çœåŒåãåŸãããšãã§ããŸããïŒ ãã¶ã@gaearonïŒ ããã¯çåŸ4ã¶æã§ãæ¬åœã®çã¿ãåŒãèµ·ãããŠããŸãã ããã¯ãå®å šã«å®å šãªåé¿çããªãReact 16ã§ã®APIã®é倧ãªå€æŽã§ããããããã°ãšããŠããªã説æã§ãããšæããŸãã
@craigkovatchã€ã³ã©ã€ã³ã®äŸãã©ã®ããã«è§£æ±ºããã®ãããŸã èå³ããããŸãã ãããã¢ãããããã¯ã¹ã®ãµã€ãºãæŒãäžããŠãããšããŸãããã äœããã€ã³ã©ã€ã³åããããšã¯ããã®ãµã€ãºãèæ ®ããŠã¬ã€ã¢ãŠãå ã§äœããæŒãäžãããããéèŠã§ãã ãã ãããŒããããšã¯ã§ããŸããã
ããããªãŒããŒã枬å®ããåããµã€ãºã®ç©ºçœã®ãã¬ãŒã¹ãã«ããŒãæ¿å ¥ããŠäžã«æããããšããå¯èœæ§ããããŸãããããã¯äººã ãè¡ãããšã§ã¯ãããŸããã
ã§ã¯ãããããªãŒããŒããã¿ã³ã®ãã暪ãªã©ãã³ã³ãã³ããæå®ã®äœçœ®ã«å±éããå¿ èŠãããå Žåãã©ã®ããã«è§£æ±ºããŸããïŒ ããã§æ©èœãããã¿ãŒã³ã¯ã©ã¡ãã®å Žåã§ãæ©èœãããšæãããã®ã§ã1ã€ã®ãã¿ãŒã³ããå§ãããŸãã
äžè¬çã«ãããã¯äž¡æ¹ã®ã·ããªãªã§æ©èœãããã¿ãŒã³ã ãšæããŸãã
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}
</>;
}
}
FlyoutãããŒã¿ã«ã®å Žåãããã¯æ©èœããããŒã¿ã«ã«ã«ãŒãœã«ãåããããšãã«ã€ãã³ãã®äžã«ããŠã¹ã眮ãããšã¯ãããŸããã ãããããã£ãšéèŠãªããšã¯ãããŒã¿ã«ã§ã¯ãªããã€ã³ã©ã€ã³ãã©ã€ã¢ãŠãã§ããå¿ èŠãããå Žåã«ãæ©èœããããšã§ãã stopPropagationã¯å¿ èŠãããŸããã
ã§ã¯ããŠãŒã¹ã±ãŒã¹ã§æ©èœããªããã®ãã¿ãŒã³ã«ã€ããŠã¯ã©ãã§ããããã
@sebmarkbageã¯ãããŒã¿ã«ããŸã£ããç°ãªãæ¹æ³ã§äœ¿çšããŠããã <body>
ã®æåŸã®åãšããŠããŠã³ããããã³ã³ãããŒã«ã¬ã³ããªã³ã°ããŸãããã®ã³ã³ãããŒã¯ãå Žåã«ãã£ãŠã¯z-indexã䜿çšããŠé
眮ãããŸãã Reactã®ããã¥ã¡ã³ãã¯ããããèšèšæå³ã«è¿ãããšã瀺åããŠããŸãã ã€ãŸããDOMå
ã®ãŸã£ããç°ãªãå Žæã«ã¬ã³ããªã³ã°ããŸãã ç§ãã¡ã®ãŠãŒã¹ã±ãŒã¹ã¯ããã®ã¹ã¬ããã«å±ããè°è«ã«åå䌌ãŠããããã«ã¯æããŸããã ããããäžç·ã«ãã¬ã€ã³ã¹ããŒãã³ã°/ãã©ãã«ã·ã¥ãŒãã£ã³ã°ãè¡ãããå Žåã¯ãå¥ã®ãã©ãŒã©ã ã§ããã«è©±ãåãããšãã§ããã°å¹žãã§ãã
ç§ã®ãŠãŒã¹ã±ãŒã¹ã¯äž¡æ¹ã§ã¯ãããŸããã æã«ã¯äžæ¹ãæã«ã¯ä»æ¹ã ãããé¢é£æ§ãããçç±ã§ãã
<Flyout />
ã¯ãããã£ã®æåŸã®åã«ã¬ã³ããªã³ã°ãããã©ãããéžæã§ããŸãããããŒã¿ã«èªäœãããããŒãããã³ã³ããŒãã³ãã®åã§ã¯ãªãããããŒãããã³ã³ããŒãã³ãã®å
åŒã«æã¡äžããéããã·ããªãªã¯æ©èœããŸãã
ãããäžäŸ¿ã§ãæ·±ããã¹ããããã³ã³ããŒãã³ãããç©äºããã¬ããŒãããæ¹æ³ãå¿ èŠãªãšãããã£ãšããããã·ããªãªããããšæããŸããããã®ã·ããªãªã§ã¯ãã³ã³ããã¹ããäžéç¹ããã®ã³ã³ããã¹ãã§ããããšã«ããããåé¡ã¯ãããŸããã ããããç§ã¯ãããã2ã€ã®å¥ã ã®åé¡ãšèããŠããŸãã
ãã®ããã«ã¹ããã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ã§ããªãããŸãåŠçã§ãããšæããŸãããããã¯ç¹ã«ã©ã€ãã©ãªã«ãšã£ãŠã¯ã¡ãã£ãšé¢åã§ãã
ããŒã¿ã«èªäœãããããŒãããã³ã³ããŒãã³ãã®åã§ã¯ãªãããããŒãããã³ã³ããŒãã³ãã®å åŒã«æã¡äžããéããã·ããªãªã¯æ©èœããŸãã
ç§ããã©ããŒãããã©ããããããªãã ããšãã°ãkeyDownã€ãã³ããäºæããªãDOMããªãŒããããªã³ã°ãããšããåé¡ããŸã ãããŸãã
@jquenseç§ã®äŸã§ã¯ãã¹ãããã¯ãŸã Barã³ã³ããŒãã³ãå
ã«ããããã <Form><Bar /></Form>
ãããªãã©ãŒã ããã³ã³ããã¹ããååŸããããšã«æ³šæããŠãã ããã
ããŒã¿ã«ãããã¥ã¡ã³ãæ¬æã«ã¬ã³ããªã³ã°ãããå Žåã§ãã
ã€ãŸãã2ã€ã®éæ¥ïŒããŒã¿ã«ïŒã®ãããªãã®ã§ããæ·±ã->ããŒã®å åŒ->ããã¥ã¡ã³ãã®æ¬æã§ãã
ãããã£ãŠãããŒã¿ã«ã®ã³ã³ããã¹ãã¯äŸç¶ãšããŠãã©ãŒã ã®ã³ã³ããã¹ãã§ãããã€ãã³ããããªã³ã°ãã§ãŒã³ãåæ§ã§ãããã©ã¡ãããããŒããããã®ã®ã³ã³ããã¹ãã§ã¯ãããŸããã
ã¯ããç³ãèš³ãããŸãããããããèŠéããŸããð³ç§ããããæ£ããèªãã§ãããªããããªãã¯ãŸã <Slot>
泡ç«ã£ãŠããã§ãããïŒ ã¢ãŒãã«ãã€ã¢ãã°ã®å Žåããããããããªã³ã°ã¯å¿
èŠãªããšæããŸãããããã¯ééããªãåªããŠããŸãã ã¹ã¯ãªãŒã³ãªãŒããŒã®èŠ³ç¹ããèããã®ãšåãããã«ãã¢ãŒãã«ã®å€åŽã®ãã¹ãŠããã¢ããããŠããéã¯å転ãããããšèããŠããŸãã ããããŸããããã®å Žåããããªã³ã°ã¯èœãšãç©Žã ãšæããŸãããã€ã¢ãã°å
ã®ã¯ãªãã¯ãã©ãã§ããããªã³ã°ããããšã¯èª°ãæåŸ
ããŠããŸããã
ããã§ã®åé¡ã¯ããŒã¿ã«ã§ã¯ãªããããããŸããããããªãŒéã§ã³ã³ããã¹ããå
±æããããã®è¯ãæ¹æ³ã¯ãããŸãããïŒ æèããã®äžéšReactDOM.render
ã¯ã¢ãŒãã«ã«ã¯æ¬åœã«åé¡ãªãããšã«ããããã«ã€ããŠã®ãããæ£ãããèãæ¹ãããããŸãã...
ããã§ã®ç§ã®èãã¯ãããããŸã ã¢ãŒãã«ããdivãããã£ãããã¥ã¡ã³ãããŠã£ã³ããŠã«è³ããããå€å°ã®ãããªã³ã°ããããšããããšã§ãã ãããŠãæŠå¿µçã«ã¯ããã¬ãŒã ãè¶ ããŠãå容ãŠã£ã³ããŠãªã©ã«å°éããŸãã
ããã¯ãARTãGLã§ã¬ã³ããªã³ã°ãããã³ã³ãã³ãïŒããã³ããçšåºŠReact NativeïŒã®ããã«ããããã®ã»ãã³ãã£ã¯ã¹ãååŸããããã®æ¢åã®ãããã³ã°ããªãŒããªãå¯èœæ§ãããå Žåã«ã¯çè«çã§ã¯ãããŸããã ãããã£ãŠããããããã«ã®å Žæã§ãããšèšãæ¹æ³ãå¿ èŠã§ãã
äžéšã®ã¢ããªã§ã¯ãã¢ãŒãã«ã«ã¢ãŒãã«ããããŸãã ããšãã°ãFBã«ã¯ãã¢ãŒãã«ã®äžã«ããå¯èœæ§ã®ãããã£ãããŠã£ã³ããŠãããããã¢ãŒãã«ããã£ãããŠã£ã³ããŠã®äžéšã§ããå¯èœæ§ããããŸãã ãããã£ãŠãã¢ãŒãã«ã§ãããããªãŒã®ã©ãã«å±ãããã«é¢ããŠäœããã®ã³ã³ããã¹ãããããŸãã å®å šã«ã¹ã¿ã³ãã¢ãã³ã«ãªãããšã¯ãããŸããã
ã ãããšãã£ãŠãã€ãã³ãã®ãããªã³ã°ãšã³ã³ããã¹ãã«2ã€ã®ç°ãªãã»ãã³ãã£ã¯ã¹ãèšå®ã§ããªãããã§ã¯ãããŸããã ããã¯äž¡æ¹ãšãããã«ã€ããŠæçœã§ãããããªãã¯ä»ãªãã§äžæ¹ãããŒã¿ã«åããããšãã§ããŸãã
äž¡æ¹ãåããã¹ããã©ãããšãä¿èšŒããããšã¯ããã©ãŠã¶ãšåãããã«ãŠãŒã¶ãŒã¹ããŒã¹ã€ãã³ãã«å¯ŸããŠã€ãã³ããããªã³ã°ãå®å šã«å®è£ ã§ããããšãæå³ãããããéåžžã«åŒ·åã§ãã
ããšãã°ãããã¯ä»æ¥ã®ããŸããŸãªReduxã³ã³ããã¹ãã§çºçããŸãã this.context.dispatch("Hover")
ããŠãŒã¶ãŒã¹ããŒã¹ã€ãã³ãã®ãããªã³ã°ã§ãããšæ³åããŠãã ããã ã³ã³ããã¹ãã®äžéšãšããŠReactã€ãã³ããå®è£
ããããšãã§ããŸãã ç§ããããåãããã«äœ¿ãããšãã§ãããšèããã®ã¯çã«ããªã£ãŠããŸãããããŠä»ãããããæ¹æ³ã§ããªãã¯ããããããšãã§ããŸãã ãããã®2ã€ã®ã³ã³ããã¹ãããã©ãŒã¯ããå Žåãéåžžã®ã³ã³ããã¹ããšäžŠè¡ããŠDOMæ§é ã«åŸãå¥ã®ãŠãŒã¶ãŒã¹ããŒã¹ã³ã³ããã¹ãAPIãäœæãããå¯èœæ§ããããŸãã
ã ãããç§ã¯ã¹ãããã®ããšã§ååãã©ããã確èªããããã«å°ãããã·ã¥ããŠããã®ã§ããaïŒãšã«ããã©ã®ã³ã³ããã¹ããããªã³ã°ãçºçããããæ瀺ããå¿ èŠãããããã§ãã bïŒäžçããã©ãŒã¯ãã2ã€ã®ã³ã³ããã¹ãã·ã¹ãã å šäœãæã€ããšãåé¿ã§ããŸãã
å ·äœçã«ã¯ãåæãã©ãŒã«ã¹ã€ãã³ãã§stopPropagationãåŒã³åºããŠãããŒã¿ã«ããã®ãããªã³ã°ãé²æ¢ãããšãïŒdocumentäžã®Reactã®ãã£ããã£ããããã³ãã©ãŒã®ãã€ãã£ããã©ãŒã«ã¹ã€ãã³ãã§ãstopPropagationãåŒã³åºãããŸããã€ãŸããäžã®å¥ã®ãã£ããã£ããããã³ãã©ãŒã«ã¯å°éããŸããã§ããã
ã ãã³ãã©ãŒã#documentã«ç§»åããããšã§ä¿®æ£ããŸããããReactã®ã€ãŸå ãèžãŸãªãããã«ããããŸã§ã¯ç¹ã«åé¿ããŠããŸããã
@craigkovatch ãonFocusCapture
ã€ãã³ãã䜿çšããŸãããïŒ ç§ã®åé¿çã§ã¯ããã£ããã£ãããã€ãã³ããåæ¢ããã¹ãã§ã¯ãããŸããã ãããã©ã®ããã§ãã£ããããããŠããªããããªãã®åé¡ã解決ããããã«äœããããã«ã€ããŠã®ãã詳现ãªäŸãæäŸã§ããŸããïŒ
ãŸããç§ã®ã³ãŒãã«ã¯blur
ã€ãã³ãã®åæ¢ã«åé¡ããããšæããŸã-åæ¢ãã¹ãã§ã¯ãããŸããã ããã§ãç§ã¯ãã®è³ªåãããæ·±ã調æ»ããããä¿¡é Œã§ãã解決çãèŠã€ããããšããŸãã
@ kib357åé¿çã«åé¡ãããããšã瀺åããŠããããã§ã¯ãããŸããããReactã«ã¯å¥ã®ãã°ããããšæããŸãïŒã€ãŸãããããªã³ã°ãã§ãŒãºã®åæãã©ãŒã«ã¹ã€ãã³ãã§stopPropagationãåŒã³åºããšãã«ããã£ããã£ãã§ãŒãºã§ãã€ãã£ããã©ãŒã«ã¹ã€ãã³ãã®äŒæããã£ã³ã»ã«ããªãã§ãã ããïŒã
åé¡ã®ã³ãŒãã¯ããã€ãã£ãã®ãã£ããã£ã€ãã³ããªã¹ããŒãã€ãŸãdocument.body.addEventListener('focus', handler, true)
ãã£ããã£ããããã³ãã©ãŒã䜿çšãããšããäºå®ãèãããšã
ã€ãŸããããŒã¿ã«ã¬ã³ããªã³ã°ã䜿çšããããã®2ã€ã®ç°ãªãã·ããªãªããããŸãã
çŸåšã®createPortal
APIã¯ãæåã®ã·ããªãªã®ã¿ãæºãããŠãããšæããŸãã æ°ããReact.renderã2çªç®ã«äœ¿çšãããšããææ¡ã¯äœ¿çšã§ããŸããããã¹ãŠã®ã¬ã€ã€ãŒã«å¯ŸããŠããã¹ãŠã®ãããã€ããŒã䜿çšããŠåå¥ã®ã¢ããªãäœæããã®ã¯éåžžã«è²§åŒ±ã§ãã
ãã®åé¡ã解決ããããã«æäŸã§ããè¿œå æ
å ±ã¯äœã§ããïŒ
createPortal
APIã§ææ¡ããããã©ã¡ãŒã¿ã®ã©ã®ãããªæ¬ ç¹ããããŸããïŒ
@sebmarkbageã¹ãããAPIã«é¢ããç§ã®çŽæ¥ã®è³ªåã¯ãè€æ°ã®SlotContents
ã1ã€ã®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>
</>
}
ããã«ã¯ãåé¿çãå®å
šã«èŠã€ããããšãã§ããªãã£ãæ°ããåé¡ããããŸãã äžèšã§ææ¡ãããã€ãã³ããã©ãããã¢ãããŒãã䜿çšãããšãReactSyntheticã€ãã³ãã®ã¿ãããŒã¿ã«ããã®ãããªã³ã°ããããã¯ãããŸãã ãã€ãã£ãã€ãã³ãã¯äŸç¶ãšããŠããã«ã§ãããReactã³ãŒãã¯ã»ãšãã©jQueryã¢ããªã±ãŒã·ã§ã³å
ã§ãã¹ããããŠããããã <body>
ã®ã°ããŒãã«jQuerykeyDownãã³ãã©ãŒã¯åŒãç¶ãã€ãã³ããååŸããŸãã
ãã®ãããªåç §ãä»ããŠããŒã¿ã«å ã®ãã€ãã£ãã³ã³ããèŠçŽ ã«event.stopPropagationãªã¹ããŒãè¿œå ããããšããŸããããããã¯ããŒã¿ã«å ã®ãã¹ãŠã®åæã€ãã³ããå®å šã«ç¡å¹ã«ããŸã-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
ãªã©ïŒããªãéããå
éšã§ãããªã³ã°ãã·ãã¥ã¬ãŒããããããã¬ãã«ãªã¹ããŒã1ã€ã ãæã€ããšã奜ã¿ãŸãã
@Kovenskyç§ã®ç解ã§ã¯ãjQueryã¯Reactã®ããã«ãåæãããªã³ã°ããè¡ããªãã£ãããããããã¬ãã«ã®ãªã¹ããŒã¯1ã€ããããŸããã§ããã ç§ã®DOMã€ã³ã¹ãã¯ã¿ãŒã1ã€ãæããã«ããŸããã ç§ãééã£ãŠããå Žåã¯ãããªããåç §ããŠãããã®ãèŠãŠã¿ããã§ãã
ããã¯ãå§ä»»ãããã€ãã³ãã®å Žåã«åœãŠã¯ãŸããŸãã ããšãã°ã $(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ã䜿çšããŠããã©ãŒã ãã£ãŒã«ããã¢ããªããŒã«ããŒïŒããªãŒã®ã¯ããäžïŒã«ç§»åããŠããŸãã ãã®å Žåããã€ãã³ããããŒãžã®ã³ã³ãã³ãã«æ»ã£ãŠãããªã³ã°ããããšã¯æ¬åœã«æãŸãããããŸãããããã©ãŒã ã³ã³ããã¹ããããã«åãããŠäœ¿çšââããããšã¯ééããããŸããã ç§ã®å®è£ ã¯ãã³ã³ããã¹ãã䜿çšããã¹ããã颚ã®ãã®ã§ã...
@sebmarkbage unstable_renderSubtreeIntoContainer
ã¯ãéå±€å
ãŸãã¯å¥ã®ããã±ãŒãžåããããã¬ãŒã ã¯ãŒã¯ã®äžéšãšããŠãã³ã³ããŒãã³ãã®äœçœ®ã«é¢ä¿ãªããéå±€ã®æäžäœã«çŽæ¥ã¢ã¯ã»ã¹ã§ããããã«ããŸããã
æ¯èŒãããšãã¹ããããœãªã¥ãŒã·ã§ã³ã«ã¯ããã€ãã®åé¡ããããŸãã
ãŠãŒã¹ã±ãŒã¹ããããŸãïŒãããããã§ã«è¿°ã¹ããã®ãšäŒŒãŠããŸãïŒã
ãŠãŒã¶ãŒãããªããªããã䜿ã£ãŠããŠã¹ã§ç©äºãéžæã§ããè¡šé¢ããããŸãã ããã¯åºæ¬çã«100ïŒ
ã®å¹
/é«ãã§ãããç§ã®ã¢ããªã®ã«ãŒãã«ããã onMouseDown
ã€ãã³ãã䜿çšããŸãã ãã®ãµãŒãã§ã¹ã«ã¯ãã¢ãŒãã«ãããããããŠã³ãªã©ã®ããŒã¿ã«ãéããã¿ã³ããããŸãã ããŒã¿ã«å
ã®mouseDownã€ãã³ãã¯ãå®éã«ã¯ã¢ããªã®ã«ãŒãã«ãããªããªãéžæã³ã³ããŒãã³ãã«ãã£ãŠã€ã³ã¿ãŒã»ãããããŸãã
ç§ã¯åé¡ã解決ããããã«å€ããèŠãŸãïŒ
ä»ã®ãšãããç§ã®è§£æ±ºçã¯ã€ãã³ããé€å€ããããšã§ãã
const appRootNode = document.getElementById('root');
const isInPortal = element => isNodeInParent(element, appRootNode);
handleMouseDown = e => {
if (!isInPortal(e.target)) {
return;
}
...
};
ããã¯æããã«ç§ãã¡å šå¡ã«ãšã£ãŠæåã®è§£æ±ºçã§ã¯ãªãããã¹ããããããŒã¿ã«ãããå Žåã¯ããŸãè¯ããããŸããããç§ã®çŸåšã®ãŠãŒã¹ã±ãŒã¹ïŒçŸåšå¯äžã®ãã®ïŒã§ã¯æ©èœããŸãã æ°ããã³ã³ããã¹ãã©ã€ãã©ãªãè¿œå ããããããã解決ããããã«è€éãªãªãã¡ã¯ã¿ãªã³ã°ãå®è¡ãããããããããŸããã ç§ã®ãœãªã¥ãŒã·ã§ã³ãå ±æãããã£ãã ãã§ãã
ãã®ã¹ã¬ããã®ä»ã®å Žæã§èª¬æãããŠããããã«ãããããã³ã°ã€ãã³ãã®ãããªã³ã°ãå®è¡ããããšãã§ããŸããã
ããããç§ãééããŠãããã1ã€ã®äžèŠåä»ãªåé¡ã¯ã onMouseEnter
SyntheticEventã§ããããã¯ããã«ããŸããã ããããããã§èª¬æããããã«ã from
ã³ã³ããŒãã³ãã®å
±éã®èŠªããto
ã³ã³ããŒãã³ãã«ãã©ããŒã¹ããŸãã ã€ãŸããããŠã¹ãã€ã³ã¿ãŒããã©ãŠã¶ãŒãŠã£ã³ããŠã®å€åŽããå
¥ããšãDOMã®äžéšããcreatePortalã®ã³ã³ããŒãã³ãã«è³ããŸã§ããã¹ãŠã®onMouseEnter
ãã³ãã©ãŒããã®é åºã§ããªã¬ãŒãããããããçš®é¡ã®ã€ãã³ããçºçããŸãã unstable_renderSubtreeIntoContainer
ãã£ãããšã¯ãããŸããã onMouseEnter
ã¯ããã«ããªããããããŒã¿ã«ã¬ãã«ã§ãããã¯ããããšã¯ã§ããŸããã ïŒ onMouseEnter
ã€ãã³ãã¯ä»®æ³éå±€ãå°éãããæ¬æã®ã³ã³ãã³ããé çªã«äžŠã¹ãããµãããªãŒã«çŽæ¥éãããããããã¯unstable_renderSubtreeIntoContainer
åé¡ã§ã¯ãªãããã§ããïŒ
onMouseEnter
ã€ãã³ããDOMéå±€ã®æäžäœããäŒæããããããŒã¿ã«ãµãããªãŒã«çŽæ¥è¿åãããããã®ãé²ãæ¹æ³ã«ã€ããŠèª°ããã¢ã€ãã¢ãæã£ãŠããå Žåã¯ãç§ã«ç¥ãããŠãã ããã
@JasonGoreç§ããã®æ¯ãèãã«æ°ã¥ããŸããã
äŸãã°ã
divãonMouseOverãããªã¬ãŒãããšãã«ã¬ã³ããªã³ã°ãããã³ã³ããã¹ãã¡ãã¥ãŒããããŸãã次ã«ãã¡ãã¥ãŒã®é ç®ã®1ã€ãã¯ãªãã¯ããŠãcreatePortalã§ã¢ãŒãã«ãéããŸãã ããŠã¹ããã©ãŠã¶ãŠã£ã³ããŠããå€ããšãonMouseLeaveã€ãã³ããã³ã³ããã¹ãã¡ãã¥ãŒãŸã§äŒæããã³ã³ããã¹ãã¡ãã¥ãŒïŒãããã£ãŠã¢ãŒãã«ïŒãéããŸã...
å šäœãïŒãªã³ã¯ãšããŠïŒã¯ãªãã¯ã§ããããã«ããããªã¹ãã¢ã€ãã ãããã®ãšåãåé¡ããããŸããããååã®äžã®ã©ãã«ã«åé€ãã¿ã³ãããã確èªã®ããã«ã¢ãŒãã«ãéããŸãã
ç§ã®å¯äžã®è§£æ±ºçã¯ã次ã®ããã«ã¢ãŒãã«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 ïŒ
ãããªã³ã°ãšãã£ããã£ãäžè¬çã«ã©ãã»ã©åœ¹ç«ã€ãã¯ããããŸããïŒReactã¯å éšã§ãããªã³ã°ã«äŸåããŠããããšãç¥ã£ãŠããŸãïŒ-確ãã«æŽå²ã¯ãããŸãããã³ãŒã«ããã¯ãæž¡ãããããå ·äœçãªã€ãã³ããäŒæããããšæããŸãïŒããšãã°ãããããäžå¿ èŠãªä»²ä»è ã®æãä»ããŠãã®ãããªãã®ãããã®ã§ãããã«ã¢ãããŸãã¯ãã£ããã£ããŠã³ãããïŒã https://css-tricks.com/dangers-stopping-event-propagation/ã®ãããªèšäºããããç§ã¯äœãžã®äŒæã«äŸåããã¢ããªã«åãçµãã§ããŸããäž»ã«ãå€åŽããã¯ãªãã¯ãããšãã«ç©ãéããããã§ãããç§ã¯ããããã¹ãŠã®äžã«é衚瀺ã®ãªãŒããŒã¬ã€ã眮ãããããã¯ãªãã¯ããŠéããŸãã ãã¡ãããReactã®ããŒã¿ã«ã䜿çšããŠãã®ãããªç®ã«èŠããªããªãŒããŒã¬ã€ãäœæããããšã¯ã§ããŸããã§ãã...
ããã«ã¯ã¡ã³ããã³ã¹ã®æªå€¢ããããŸããæ°ããã€ãã³ããDOMã«è¿œå ããããšãäžèšã®ææ³ã§ãå°å°ããããããŒã¿ã«ã¯ãã¡ã³ããã³ã¹æ åœè ãïŒåºç¯ãªïŒãã©ãã¯ãªã¹ãã«è¿œå ã§ããããã«ãªããŸã§ããããã®æ°ããã€ãã³ããããªãŒã¯ãããŸãã
ããã«ã¯ã察åŠããå¿ èŠã®ããäž»èŠãªèšèšäžã®åé¡ããããŸãã ã¯ãã¹ããŒã¿ã«ãããªã³ã°ããªããã€ã³ãŸãã¯ãªããã¢ãŠãããæ©èœã¯ãäŸç¶ãšããŠç§ã«ãšã£ãŠæè¯ã®APIãªãã·ã§ã³ã®ããã§ãã å®è£ ã®é£ããã«ã€ããŠã¯ããããããŸãããã1幎以äžçµã£ãä»ã§ããTableauã§ããã«é¢ããæ¬çªç°å¢ã®ãã°ãçºçããŠããŸãã
ã¢ãŒãã«ããã®ç§ã®ãã©ãŒã ãå¥ã®ãã©ãŒã ãéä¿¡ããŠããçç±ãèŠã€ããããã«2æéãè²»ãããŠãã ããã
ã€ãã«ãã®åé¡ã®ãããã§ãããç解ããŸããïŒ
onSubmit
äŒæããã€å¿
èŠã«ãªããã確èªããã®ã«æ¬åœã«èŠåŽããŠããŸãã ã»ãšãã©ã®å Žåãæ©èœãšããããã¯ãã°ã®ããã«ãªããŸãã
å°ãªããšããããã¥ã¡ã³ãã«
ããŒã¿ã«ãä»ããã€ãã³ããããªã³ã°ã¯åªããæ©èœã§ãããã€ãã³ãã®äŒæãé²ãããå ŽåããããŸãã onSubmit={(e) => {e.stopPropagation()}}
è¿œå ããããšã§ãããéæã§ããŸã
ããã«ã+1ã ç§ãã¡ã¯ã䜿çšããŠããdraftjsãã¯ãªãã¯å¯èœãªããã¹ã瀺ãã¢ãŒãã«ã§heavillyã ãããŠããã©ãŒã«ã¹ãéžæãå€æŽãããŒæŒäžãªã©ã®ã¢ãŒãã«ã®ãã¹ãŠã®ã€ãã³ãã¯ããšã©ãŒã§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ã®åæã€ãã³ããããŒã¿ã«ãããã¬ãŒã³ãªãŒã«ãDOMããªãŒã«äŒæããããšã¯æ©èœããªããšæããŸãã
ããŒã¿ã«ã¯é·ãé䜿çšãããŠããªããããããã©ã«ãã®åäœããããŒã¿ã«ã®å¢çãè¶ããŠäŒæããªããã«å€æŽããã«ã¯é ãããå¯èœæ§ããããŸãã
ãããŸã§ã®ãã¹ãŠã®è°è«ã«åºã¥ããŠãç§ã®æãç°¡åãªææ¡ã¯ïŒãŸã ïŒãã®åŸã次ã®ãšããã§ããããŒã¿ã«ã®å¢çãè¶ ããŠãã¹ãŠã®ã€ãã³ãã®äŒæãé²æ¢ããcreatePortalã«ãªãã·ã§ã³ã®ãã©ã°ãè¿œå ããŸãã
ããå ç¢ãªãã®ã¯ãæ®ããåæ¢ããªãããå¢çããçªç Žãã§ããããã«ããå¿ èŠãããã€ãã³ãã®ãã¯ã€ããªã¹ããæäŸããæ©èœã§ããå¯èœæ§ããããŸãã
@gaearon ReactããŒã ãå®éã«ãããåŒãåããããšãã§ããæç¹ã«ããŸããïŒ ããã¯ããã10ã®åé¡ã§ãããããã«ã€ããŠã¯ãã°ããã®éãããªãããäœãèããŠããŸããã
ç§ã¯ããã«ç§ã®ãµããŒããè¿œå ããããšæããŸãããããŠãReactã³ã³ããã¹ããšDOMã€ãã³ããããªã³ã°ã®äž¡æ¹ãããŒã¿ã«åããæ¹ãã³ã³ããã¹ãã ããããŒã¿ã«åãããããæŠå¿µçã«æå³ããããšäž»åŒµããæšå¹Žã®@sebmarkbageã®ã³ã¡ã³ãã«åæã
DOMå ã®ããå Žæããå¥ã®å Žæã«ã³ã³ããã¹ããããŒã¿ã«åããæ©èœã¯ãããŒã«ããããããããããŠã³ããããŒã«ãŒãããã€ã¢ãã°ãªã©ããªãŒããŒã¬ã€ã®ã³ã³ãã³ããã«ãã£ãŠèšè¿°ããããã®ã³ã³ããã¹ãã§ã¬ã³ããªã³ã°ããããããããçš®é¡ã®ãªãŒããŒã¬ã€ãå®è£ ããã®ã«åœ¹ç«ã¡ãŸããåŒãéã ã³ã³ããã¹ãã¯Reactã®æŠå¿µã§ããããããã®ã¡ã«ããºã ã¯Reactã®åé¡ã解決ããŸãã äžæ¹ãDOMã€ãã³ãã®ãããªã³ã°ãDOMå ã®ããå Žæããå¥ã®å Žæã«ããŒã¿ã«åããæ©èœã¯ãDOMæ§é ãæ瀺çã«èšå®ãããã®ãšã¯å¥ã®ãã®ã§ãããã®ããã«èŠãããããåã£ãããªãã¯ã§ãã ããã«ãããDOMã®å¥ã®éšåã«å§ä»»ããå Žåã«ãå§ä»»ã«DOMã€ãã³ããããªã³ã°ã䜿çšããéã®åé¡ã解決ãããŸãã Reactã䜿çšããŠããå Žåã¯ããªãŒããŒã¬ã€ã®å åŽããå€åŽã«ãããªã³ã°ããDOMã€ãã³ãã«äŸåããã®ã§ã¯ãªãããšã«ããã³ãŒã«ããã¯ïŒãŸãã¯ã³ã³ããã¹ãïŒã䜿çšããå¿ èŠããããŸãã ä»ã®äººãææããŠããããã«ãæå³çãŸãã¯æå³ããã«ããªãŒããŒã¬ã€å ã§çºçããã€ãã³ãã«ãå°éãããŠåŠçããããšã¯ãã£ãã«ãããŸããã
DOMã€ãã³ãã®ãããªã³ã°ã¯ãäž»ã«DOMã€ãã³ããDOMã¿ãŒã²ããã«äžèŽãããåé¡ã解決ããŸãã ãã¹ãŠã®ã¯ãªãã¯ã¯ãå®éã«ã¯ãã¹ããããèŠçŽ ã®ã»ããå šäœã®ã¯ãªãã¯ã§ãã é«ã¬ãã«ã®å§ä»»ã¡ã«ããºã ã§ããIMOãšããŠèããã®ã¯æåã§ã¯ãªããDOMã€ãã³ãã䜿çšããŠReactã³ã³ããŒãã³ãã®å¢çãè¶ããŠå§ä»»ããããšã¯ãã³ã³ããŒãã³ããDOMã®äºæž¬å¯èœãªããããã¬ã³ããªã³ã°ããããã«äœ¿çšãããå°ããªãã©ã€ããŒããã«ããŒã³ã³ããŒãã³ãã§ãªãéããåªããã«ãã»ã«åã§ã¯ãããŸããã
event.target === event.currentTargetã¯ããã®åé¡ã®è§£æ±ºã«åœ¹ç«ã¡ãŸãã ããããããã¯æ¬åœã«é çã®çš®ã§ãã
unstable_renderSubtreeIntoContainer
ã䜿çšããŠcreatePortal
ã䜿çšããããã«ããããªãŒããŒã³ã³ããŒãã³ãã移è¡ããããšããŠãããšãã«ãããã¯ä»æ¥ç§ãèŠãããŸããã åé¡ã®ã³ã³ããŒãã³ãã«ã¯ãã©ãã°å¯èœãªèŠçŽ ãå«ãŸããŠãããå¥ã®ãã©ãã°å¯èœãªèŠçŽ ã®åå«ãšããŠã¬ã³ããªã³ã°ãããŸãã ããã¯ã芪èŠçŽ ãšããããªãŒããŒèŠçŽ ã®äž¡æ¹ã«ããŠã¹ãšã¿ããã®ã€ãã³ããã³ãã©ãŒãå«ãŸããŠããããšãæå³ããŸãããããã®ãã³ãã©ãŒã¯ãããŒã¿ã«ã®ããããªãŒããŒãšå¯Ÿè©±ãããšãã«äž¡æ¹ãšãèµ·åãéå§ããŸããã
unstable_renderSubtreeIntoContainer
ã¯å»æ¢ãããŠããããïŒïŒïŒã代æ¿ãœãªã¥ãŒã·ã§ã³ãå¿
èŠã§ããäžèšã®åé¿çã¯ãããããå®è¡å¯èœãªé·æçãªãœãªã¥ãŒã·ã§ã³ã§ã¯ãªãããã§ãã
ããïŒ ãã®ãã¹ãŠã®ææ¡ãããããšãïŒ
ããã¯ç§ã®åé¡ã®1ã€ãä¿®æ£ããã®ã«åœ¹ç«ã¡ãŸããã
ReactããŒã ã®éèŠæ§ãšèœåã«ã€ããŠã®çŽ æŽãããæçãªèšäºãèªã¿ããã§ããïŒ éçºã«èå³ã®ããæ¹ãªãã©ãªãã§ãã圹ã«ç«ãŠãã°ãšæããŸãã 幞éãïŒ
IMOã¯ãå€ãã®å ŽåãããŒã¿ã«ã§ã³ã³ããã¹ããžã®ã¢ã¯ã»ã¹ãæäŸããŸãããã€ãã³ããããã«ã¢ãããããããªãå ŽåããããŸãã Angular 1.xã䜿çšããŠãããšãã $scope
ãšãã³ãã¬ãŒãæååãåãåãããã®ãã³ãã¬ãŒããã³ã³ãã€ã«/ã¬ã³ããªã³ã°ããŠæ¬æã«è¿œå ããç¬èªã®ãããã¢ãããµãŒãã¹ãäœæããŸããã ãã®ãµãŒãã¹ã䜿çšããŠãã¢ããªã±ãŒã·ã§ã³ã®ãã¹ãŠã®ãããã¢ãã/ã¢ãŒãã«/ããããããŠã³ãå®è£
ããŸããããã€ãã³ããããªã³ã°ã®æ¬ åŠãèŠéããããšã¯äžåºŠããããŸããã§ããã
stopPropagation()
åé¿çã¯ã window
ãã€ãã£ãã€ãã³ããªã¹ããŒãããªã¬ãŒãããªãããã«èŠããŸãïŒãã®å Žåã react-dnd-html5-backend
ã«ãã£ãŠè¿œå ãããŸãïŒã
ãã®åé¡ã®æå°éã®åçŸã¯æ¬¡ã®ãšããã§ãïŒ https ïŒ
ããŒã¿ã«éã§ã®åæãããªã³ã°ãåé¿ããæ¹æ³ãæäŸããèšç»ããªãå Žåããããã誰ãããã€ãã£ãã€ãã³ããããªã³ã°ãå£ããªãåé¿çãæã£ãŠããŸããïŒ
stopPropagationïŒïŒã®åé¿çã¯ããŠã£ã³ããŠäžã®ãã€ãã£ãã€ãã³ããªã¹ããŒãããªã¬ãŒããã®ãé²ãããã«èŠããŸã
æ£ããã :(
ããŒã¿ã«éã§ã®åæãããªã³ã°ãåé¿ããæ¹æ³ãæäŸããèšç»ããªãå Žå
ã³ã¢ããŒã ã®æ²é»ã«ãããããããç§ãšãã®ã¹ã¬ããã®ä»ã®å€ãã®äººã ã¯ããã®ãããªèšç»ãããããšã_æ¬åœã«æãã§ããŸã_ã
ãããã誰ãããã€ãã£ãã€ãã³ãã®ãããªã³ã°ãå£ããªãåé¿çãæã£ãŠããŸããïŒ
ç§ã®ããŒã ã®åé¿çã¯ããã®æçœãªåé¡ã®ããã«ããŒã¿ã«ãå®å šã«çŠæ¢ããããšã§ããã ã¢ããªã®ä»ã®ã³ã³ããã¹ãå ã«ååšããã³ã³ãããŒãžã®ããã¯ãåãããã€ã³ãæ瀺ãããããã«ãŒãã¬ãã«ã®ã³ã³ããã¹ããç¡æã§ååŸã§ããŸãã æåã§æž¡ãä»ã®ãã¹ãŠã çŽ æŽããããšã¯èšããŸããããç¡æå³ãªã¢ã°ã©ãããã€ãã³ããã³ãã©ãŒãããåªããŠããŸãã
ã³ã¢ããŒã ã®èª°ãã«ããæåŸã®å¿çãã17ãæãçµã¡ãŸã@ sebmarkbageãŸãã¯@gaearon
ç§ã®ããŒã ã®åé¿çã¯ããã®æçœãªåé¡ã®ããã«ããŒã¿ã«ãå®å šã«çŠæ¢ããããšã§ããã ã¢ããªã®ä»ã®ã³ã³ããã¹ãå ã«ååšããã³ã³ãããŒãžã®ããã¯ãåãããã€ã³ãæ瀺ãããããã«ãŒãã¬ãã«ã®ã³ã³ããã¹ããç¡æã§ååŸã§ããŸãã æåã§æž¡ãä»ã®ãã¹ãŠã çŽ æŽããããšã¯èšããŸããããç¡æå³ãªã¢ã°ã©ãããã€ãã³ããã³ãã©ãŒãããåªããŠããŸãã
ã«ã¹ã±ãŒãå°éå ·ã«é Œãããšãªããå°éå ·ãä»ããŠã³ã³ããã¹ãããåœã®ããŒã¿ã«ãã«æž¡ãããã®äžè¬çãªã¢ãããŒãã¯èããããŸãã:(
ãã®åé¡ã«é¢é£ããŠhttps://github.com/reakit/reakitã§èŠã€ãããã°ã¯ç¡æ°ã«ãããŸããã ç§ã¯ReactPortalããã䜿çšããŠããŸãããããŒã¿ã«ãããã®èŠªã³ã³ââããŒãã³ããžã®ã€ãã³ããããªã³ã°ãå¿ èŠãªã±ãŒã¹ã¯1ã€ãèããããŸããã
ç§ã®åé¿çã¯ã芪ã€ãã³ããã³ãã©ãŒå ã§ãã§ãã¯ããããšã§ãã
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ã§åäœããããã«èŠããŸããã event.target
ãæåã§èšå®ã§ããªããããIE11ã¯çç¥ãããŠããŸãã ãããŸã§ã®ãšãããããŠã¹ããã€ã³ã¿ãŒãããŒããŒãããã€ãŒã«ã®ã€ãã³ãã®ã¿ãèæ
®ããŠããŸãã ãã©ãã°ã€ãã³ããè€è£œã§ãããã©ããããããªãã
æ®å¿µãªãããIE11ã®ãµããŒããå¿ èŠãªãããã³ãŒãããŒã¹ã§ã¯äœ¿çšã§ããŸããããä»ã®èª°ããèªåã®çšéã«åãããŠèª¿æŽã§ããå¯èœæ§ããããŸãã
ãããç¹ã«æ°ãé ããªããããªãã®ã«ããŠããã®ã¯ããããã©ã«ããã®åäœãã³ã³ããŒãã³ãããªãŒãåã³ããã«ããŠã³ããããšã§ãã 次ã®æšãåããŸãïŒ
<Link>
<Menu (portal)>
<form onSubmit={...}>
<button type="submit">
éä¿¡ãã¿ã³ãã¯ãªãã¯ãããããã©ãŒã å
ã®å
¥åãã£ãŒã«ãã§EnterããŒãæŒããã«é¢ä¿ãªãããã®ã³ã³ããŒãã³ãã®æ£ç¢ºãªçµã¿åããã§ãã©ãŒã ã®onSubmit
ãåŒã³åºãããªãçç±ã«ã€ããŠãç§ã¯äœæéã髪ãåŒã£åŒµã£ãŠããŸãã
æåŸã«ãReact Router Link
ã³ã³ããŒãã³ãã«onClick
å®è£
ãããããã©ãŠã¶ãŒã®ãªããŒããé²ãããã«e.preventDefault()
ãå®è¡ããŠããããšãåå ã§ããããšãããããŸããã ãã ããããã«ã¯ããã©ãŒã ã®éä¿¡ã§ããéä¿¡ãã¿ã³ã®ã¯ãªãã¯ã®ããã©ã«ãã®åäœããããã¯ãããšããäžå¹žãªå¯äœçšããããŸãã ãããã£ãŠãä»æ¥ç§ãåŠãã ã®ã¯ãéä¿¡ãã¿ã³ãæŒãããã®ããã©ã«ãã®ã¢ã¯ã·ã§ã³ãšããŠãonSubmitãå®éã«ãã©ãŠã¶ãŒã«ãã£ãŠåŒã³åºããããšããããšã§ãã EnterããŒãæŒããŠããéä¿¡ãã¿ã³ã®ã¯ãªãã¯ãããªã¬ãŒããããã©ãŒã ã®éä¿¡ãããªã¬ãŒãããŸãã
ããããã€ãã³ãã®ãããªã³ã°ã®é åºããããæ¬åœã«å¥åŠãªãã®ã«ããŠããããšãããããŸãã
<input>
[ããŒãæŒããŠå
¥å]<button type="submit">
[ã·ãã¥ã¬ãŒããããã¯ãªãã¯]<Menu>
[ã€ãã³ãã¯ããŒã¿ã«ã®å€éšã«äŒæããŸã]<Link>
[äŒæã¯èŠªã«å°éããŸãLink
]<Link>
[ e.preventDefault()
åŒã³åºã]ããã¯ããã§ã«DOMã«ãã¿ã³ãšãã©ãŒã ãæž¡ããã«ããããããçºçãã Link
ã¯ãããšã¯äœã®é¢ä¿ããªãããã®åäœããŸã£ãããããã¯ããã€ããããããŸããã§ããã
ç§ã«ãšã£ãŠã®è§£æ±ºçïŒèª°ããåãåé¡ã«ééããå ŽåïŒã¯ã <Menu>
ã³ã³ãã³ããonClick={e => e.stopPropagation()}
divã«ã©ããããäžè¬çã«äœ¿çšããã解決ç
ç§ã«ãšã£ãŠã®è§£æ±ºçïŒèª°ããåãåé¡ã«ééããå ŽåïŒã¯ã
<Menu>
ã³ã³ãã³ããonClick={e => e.stopPropagation()}
divã«ã©ããããäžè¬çã«äœ¿çšããã解決ç
ããâ _åé¡ã®åã ã®ã€ã³ã¹ã¿ã³ã¹_ã«ã¯åãç°¡åãªè§£æ±ºçããããŸãã_ãã°ãçµéšããæ£ããèå¥ããã_ã 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ã§æã掻çºãªåé¡ã®1ã€ã§ãã ãé¡ãããŸããããŒã ã®èª°ããããã§è²¢ç®ã§ããŸããïŒ
ç§ã®å Žåããã¿ã³ãã¯ãªãã¯ããŠãŠã£ã³ããŠã³ã³ããŒãã³ããéããšããŠã£ã³ããŠãã¯ãªãã¯ãããšãã¿ã³ãã¯ãªãã¯ãããŠç¶æ ãå€åããããããŠã£ã³ããŠãæ¶ããŸããã
ç§ã¯ReactãåããŠäœ¿çšããŸããäž»ã«ãjQueryãšvanillia JSã䜿çšããŸãããããã¯é©ãã¹ããã°ã§ãã ãã®åäœãäºæ³ãããå Žåã¯ã1ïŒ çšåºŠã«ãªãå¯èœæ§ããããŸã...
@diegohazã®2ã€ã®ãœãªã¥ãŒã·ã§ã³ã奜ãã§ãããããã§ãcreatePortal
ã¯ã€ãã³ãã®ãããªã³ã°ãåæ¢ãããªãã·ã§ã³ãããã¯ãã ãšæããŸãã
ç§ã®ç¹å®ã®ãŠãŒã¹ã±ãŒã¹ã¯ãããŒã«ãããã®onMouseLeave
ããã³onMouseEnter
ãã³ãã©ãŒãããã®åã®ããŒã¿ã«ã®åå«ã«ãã£ãŠããªã¬ãŒãããå Žåã§ãããããã¯æãŸãããããŸããã§ããã ãã€ãã£ãã€ãã³ãã¯ãããŒã¿ã«ã®åå«ãdomã®åå«ã§ã¯ãªããããããŒã¿ã«ã®åå«ãç¡èŠããããšã§ãããä¿®æ£ããŸããã
ããŒã¿ã«ã§ã®ãããªã³ã°ãåæ¢ãããªãã·ã§ã³ã®+1ã ããŒã¿ã«ãïŒåã§ã¯ãªãïŒå åŒãšããŠãã€ãã³ããªã¹ããŒãçºçããŠããã³ã³ããŒãã³ãã«é 眮ããããšãææ¡ãããŸããããå€ãã®ãŠãŒã¹ã±ãŒã¹ïŒç§ã®ãã®ãå«ãïŒã§ã¯æ©èœããªããšæããŸãã
æçµçã«ReactDOM.unstable_renderSubtreeIntoContainer
ãåé€ãããããã§ããã€ãŸãããã®åé¡ã«å¯Ÿããåççãªåé¿çã¯ããã«æ®ã£ãŠããªãããšãæå³ããŸã...
^ç§ãã¡ãå©ããŠãã ãã@ trueadm
GitHubã§pingãå®è¡ã§ããªãããã§ãð
ãããããã¢ã¯ãã£ããªTwitterã¢ã«ãŠã³ããæã£ãŠãã人ããæçš¿è
ã®1人ã«ã¿ã°ãä»ããŠãããã«ã€ããŠãã€ãŒãããå¯èœæ§ããããŸããïŒ
ãã®åé¡ã«+1ãè¿œå ããŸãã Notionã§ã¯ãçŸåšã React.createPortal
ããåã®ã«ã¹ã¿ã ããŒã¿ã«å®è£
ã䜿çšããŠãããã³ã³ããã¹ããããã€ããŒãæ°ããããªãŒã«æåã§è»¢éããŠããŸãã React.createPortal
ãæ¡çšããããšããŸããããäºæããªããããªã³ã°åäœã«ãã£ãŠãããã¯ãããŸããã
<Portal>
<MenuItem>
ã³ã³ããŒãã³ãã®å€ã«ç§»åããŠå
åŒã«ãªããšãã@sebmarkbageã®ææ¡ã¯ãåäžã®ãã¹ãã¬ãã«ã®åé¡ã解決ããã ãã§ãã ãµãã¡ãã¥ãŒãããŒã¿ã«åããè€æ°ã®ãã¹ããããïŒããšãã°ïŒã¡ãã¥ãŒé
ç®ãããå Žåãåé¡ã¯æ®ããŸãã
ãã®åé¡ã¯èªåçã«å€ããªã£ããã®ãšããŠããŒã¯ãããŠããŸãã ãã®åé¡ãåŒãç¶ã圱é¿ããå Žåã¯ãã³ã¡ã³ãïŒããã³ãããªã©ïŒ
ãã³ãã
ãã³ã¯é¢é£ããåé¡ã«ã€ããŠã³ã¡ã³ããæ®ããŸã
@mogelbrodçŸåšãããã«è¿œå ãããã®ã¯ãããŸããããæ¢åã®ã³ã³ããŒãã³ãã移è¡ããå Žåã¯ããã®ãããªãã®ïŒ ïŒ11387ïŒã³ã¡ã³ãïŒ ïŒã劥åœãšæãããŸãã
åãåé¡ã§ã®ãã³ã«ãããã©ããŒã¢ããïŒ
åé¿çã«ã€ããŠã®ã³ã³ããã¹ããããããšãã ããªãã¯ãã§ã«ãã®ãã¡ã€ã³ç¥èãæã£ãŠããã®ã§ã次ã®æè¯ã®ã¹ãããã¯ããããããªããæãæ¯ãèããšããªããèãã代æ¿æ¡ã®ããã®RFCãæžãããšã§ãïŒ https ïŒ
ããã«ããããããã
unstable_renderSubtreeIntoContainer
ã¯ãµããŒããããŠããªãã®ã§ãããã2ã€ã®è°è«ã解ãæãããŸãããã APIå šäœãåçµãããŠæŽæ°ãããªããããã³ã³ããã¹ãã®äŒæãè¿œå ããŸããã
è°è«ããããã©ã°ã®è¿œå ããŸãã¯ããããå¥ã®è§£æ±ºçãææ¡ããããã«ãReactRFCã確å®ã«å ¬éããå¿ èŠããããŸãã ãã©ããã«ç¹ã«èå³ãæã£ãŠãã人ã¯ããŸããïŒãããã@ justjake ã @ craigkovatch ããŸãã¯@jquenseïŒïŒ ããã§ãªããã°ãç§ã¯ç§ãæãã€ãããšãã§ãããã®ãèŠãã§ãããïŒ
ãã®APIãé²åãããããšã«èå³ã¯ãããŸãããRFCã®ãã©ããã«ã¯èå³ããããŸããã ã»ãšãã©ã®å Žåãããã¯å€§éã®äœæ¥ã§ãããåãå ¥ããããå¯èœæ§ã¯ã»ãšãã©ãããŸãããã³ã¢ããŒã ãå®éã«ããŒããããã«ãªãRFCãæ€èšããŠãããšã¯æããŸããã
@jquenseããã¯æ£ç¢ºã§ã¯ãªããšæããŸãã ã¯ããæ°ããAPIã®è¿œå ã¯åžžã«åé暪æçã§ãããä»ã®ãã¹ãŠã®èšç»ãããæ©èœã«åœ±é¿ãäžãããããããžã§ã³ã«æ²¿ã£ãŠããªãRFCãããŒãžããããšã¯ã»ãšãã©ãããŸããã ãããŠãããŸããããªããã®ã«ã€ããŠã¯ããŸãã³ã¡ã³ãããªãã®ã¯å ¬å¹³ã§ãã ãã ããç¹ã«ãšã³ã·ã¹ãã ãããå°éç¥èãæã£ãŠãããããã¯ã«ã¢ãããŒãããå Žåã¯ãããããèªã¿éããŸããäŸãšããŠã ïŒ//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ç§ã®ã³ã¡ã³ãã¯ãããŒã ãå€éšã®ãã£ãŒãããã¯ã«è³ãåŸããªãããšã瀺åãããã®ã§ã¯ãããŸããã Yaã¯ãããããŸãããã§ãããã ç§ã®ã³ã¡ã³ãã¯æ£ç¢ºã ãšæããŸãã RFCãªããžããªã§å®è¡ããã_process_ã¯ãä»ã®äººã ããåãå ¥ããããRFCã«ã¯ãªããŸããã ã©ã®RFCãããŒãžãããããèŠããšãããã¯å®å šã«ã³ã¢ããŒã ã¡ã³ããŒãŸãã¯fbåŸæ¥å¡ã§ãããä»ã«ã¯èª°ãããŸããã ãããå®çŸããæ©èœã¯ãéåžžã¯å°ãç°ãªããRFCããã»ã¹ã«ã¯ãŸã£ããåå ããŸããïŒå圢IDãªã©ïŒã
ä»ã®RFCãèŠãŠãããããæ©èœã®èšèšã«è²¢ç®ããŠãããšèããŠãšãŠãããããæããŸããããã³ã¡ã³ãããããšã¯ãããŸãããããããã®å€éšRFCã®åœ±é¿ãåããŸããããšç§ã¯èããŠããŸããããã«ææŠããŸãã
èšãæããã°ãç§ãã¡ã¯ã³ãã¥ããã£ç 究ã¡ã«ããºã ãšããŠéšåçã«RFCã«ã¢ãããŒãããŸãã
ããã¯éåžžã«åççã§ãããRFCãªããžããªã_its_ã¢ãããŒããšèšã£ãŠããããšã§ã¯ãªããä»ã®äººã ãRFCãäžè¬çã«ã©ã®ããã«èããŠãããã§ããããŸããã RFCããã»ã¹ã¯éåžžãããŒã ãšã³ãã¥ããã£ã®éã®ãªã³ã¯ãšã³ãã¥ãã±ãŒã·ã§ã³ã®ãã€ã³ãã§ãããæ©èœã®æ€èšãšããã»ã¹ã®èŠ³ç¹ããããããçšåºŠã®ç«¶äºã®å Žã§ãã
ã³ãã¥ããã£ã¬ããã³ã¹ã«ã€ããŠã®ãã倧ããªãã€ã³ãã¯ããŠããã 人ã ã«ã詳现ãªææ¡ãæžãã®ã«æéãè²»ãããåå¿ããŒã ããã®æ²é»ã«äŒããªããä»ã®å€éšã®åå è ã«ããããå®ãããã«é Œãããšã¯å€±æããFBãOSSã«å¯Ÿããèªèº«ã®ããŒãºã ããæ°ã«ããŠãããšããå°è±¡ãç©æ¥µçã«åŒ·ããŸãã ç§ã¯ããªãããã®ããã«æããããã¶ã€ã³ãããããªãããšãç¥ã£ãŠããã®ã§ãããã¯æªèãæŸã¡ãŸãã
RFCããã»ã¹ã次ã®ããã«ãªã£ãŠããå ŽåïŒãããã§ãæžå¿µäºé ãšãŠãŒã¹ã±ãŒã¹ã®æŠèŠã説æãããã®æ©èœãå®è£ ã§ããããã«ãªã£ããšãã«ãããããèªã¿ãŸããã æ£çŽãªãšãããããã¯çŽ æŽãããã¢ãããŒãã§ãã ã³ãã¥ããã£ã¯ãæ瀺çã«èª¬æãããŠããããšããæ©æµãåãããšæããŸããããã§ãªãå Žåãpplã¯ãä»ã®RFCããã»ã¹ãé »ç¹ã«è¡ãã®ãšåãã¬ãã«ã®é¢äžãšåå ãæ³å®ãããããå®è¡ãããªãå Žåã¯ç©æ¥µçã«èœèããŸãã ä»ã®å¯çš¿è ãããå°ãæŽå¯åããã£ããšããŠãã確ãã«ãã®å°è±¡ãæã£ãŠããŸãã
確ãã«ãç§ã¯ãã®ãã¹ãŠã«åæãããšæããŸãã ãããã¡ã¿ã¹ã¬ããã«å€ãããã¯ãããŸãããã人ã ã¯ãã®ã¹ã¬ããã«ã€ããŠpingãç¹°ãè¿ããŠããã®ã§ããããåé²ãããããã«æãå®çšçãªããšã¯ãäž¡æ¹ã«æžå¿µãæ±ããã©ã®ããã«æ©èœãããã«ã€ããŠã®ææ¡ãæžãããšã§ãã
ååã«å ¬å¹³ã§ãããããã¯RFCã§ã¡ã¿ãååŸããã®ã«é©åãªå Žæã§ã¯ãããŸãã:)
@gaearonããã¯ãçŸåšReactã§éãããŠãã6çªç®ã«è³æã®åé¡ã§ããã4çªç®ã«ã³ã¡ã³ããããŠããŸãã React 16ããªãªãŒã¹ãããŠãããªãŒãã³ããŠããã3æ³ããããã2ãæã§ãã ããã§ããReactã³ã¢ããŒã ããã®é¢äžã¯ã»ãšãã©ãããŸããã ããã ãã®æéãšèŠçãéããŠèµ·ãã£ãåŸãã解決çãææ¡ããã®ã¯ã³ãã¥ããã£æ¬¡ç¬¬ã ããšèšãã®ã¯éåžžã«åŠå®çã§ãã ããã€ãã®éåžžã«äŸ¿å©ãªã¢ããªã±ãŒã·ã§ã³ããããŸãããããã©ã«ãã§ãããã®åäœã¯èšèšäžã®èª€ãã§ãã£ãããšãèªèããŠãã ããã ãããä¿®æ£ããã®ã¯RFCã®ã³ãã¥ããã£æ¬¡ç¬¬ã§ã¯ãããŸããã
ãã®åé¡ã«ã€ããŠã³ã¡ã³ãããããšãåŸæããã³ãã¥ããã£RFCã«é¢ããææ¡ãæ€åããŸãã ããã§ããããã¯ããããæªãèãã§ãã ãã®åé¡ã¯éåžžã«ææ çã«ãªã£ãŠããããšãä»ãå ããªããã°ãªããŸããã人éãšããŠãç§ã¯ãã®åé¡ã«åãçµãã®ãé£ãããšæããŠããŸããããã¯éèŠã§ãããå€ãã®äººã ã匷ãæããŠããããšãç解ããŠããŸããã
ãã®ã¹ã¬ããã®ç¶æ ã«ã€ããŠç°¡åã«è¿ä¿¡ããŸãã
ãŸãããã®ã¹ã¬ããã§ãã©ããŒã¢ãããç¶ç¶ããªãã£ãããšã«ã³ã¡ã³ãããäžæºãæããŠãã人ã ã«è¬çœªããããšæããŸãã ãã®åé¡ãå€éšããèªãã§ãããšããããReactããŒã ãééããç¯ãããããèªããããªããç°¡åãªè§£æ±ºçã«é²ãã§ãããšããå°è±¡ã ã£ãã§ãããïŒãããŒã«å€ã1ã€è¿œå ããã ãã§ãã©ãã ãé£ããã圌ãã¯ã³ãã¥ããã£ãæ°ã«ããªãã®ã§ã2幎以äžã®éã§ãã ç§ã¯ããªãããã®çµè«ã«éãããããããªãæ¹æ³ãå®å šã«ç解ããããšãã§ããŸãã
ç§ã¯ãã®åé¡ãéåžžã«è³æãããŠããããšãç¥ã£ãŠããŸãã ããã¯ããã®ã¹ã¬ããã§äœåºŠãåãäžããããŠããŸãããããããReactããŒã ãããã倧ããªåé¡ç¹ã§ããããšãç¥ã£ãŠããã°ããã£ãšæ©ã察åŠã§ããã ãããšãã芳ç¹ããã§ãã ãããåé¡ç¹ã§ããããšã¯ããã£ãŠããŸãã人ã ã¯å®æçã«ç§ãã¡ã«ããã«ã€ããŠå人çã«ã¡ãã»ãŒãžãéã£ãããReactããŒã ãã³ãã¥ããã£ãæ°ã«ããªãæ¹æ³ã®äŸãšããŠãããä¿æãããããŸãã æ²é»ãèç«ãããããšãç§ã¯å®å šã«èªããŸããããäœããããã ãããšããé«ãŸãå§åã«ããããã®åé¡ã«çç£çã«åãçµãããšãããå°é£ã«ãªã£ãŠããŸãã
ãã®åé¡ã«ã¯åé¿çããããŸããããã«ãããç·æ¥ã«å¯ŸåŠããå¿ èŠã®ããã»ãã¥ãªãã£ã®è匱æ§ãã¯ã©ãã·ã¥ãšã¯ç°ãªããŸãã wokaroundsã¯ãç¹ã«React 16ããåã«äœæãããã³ãŒãã®åšãã§äœ¿çšããŠãããããæ©èœããããšã¯ããã£ãŠããŸãïŒãã ããçæ³çã§ã¯ãªããç ©ãããå ŽåããããŸãïŒãå€ãã®äººããå ·äœçãªæéæ å ã§å¯Ÿå¿ããªããã°ãªããªãã¯ã©ãã·ã¥ãã»ãã¥ãªãã£ã®åé¡ãšã¯ãŸã ç°ãªãã¯ã©ã¹ã®åé¡ã«ãããŸãã
ããã«ãææ¥å®è£ ã§ããç°¡åãªãœãªã¥ãŒã·ã§ã³ããããšãããã¬ãŒãã³ã°ã«ãåæããŸããã æåã®åäœãééãã ãšèããŠãïŒåæãããã©ããã¯ããããŸãããïŒã次ã®åäœã§ããŸããŸãªãŠãŒã¹ã±ãŒã¹ãåŠçããããã®åºæºã¯ããã«é«ããªããŸãã ããã€ãã®ã±ãŒã¹ãä¿®æ£ããä»ã®ã±ãŒã¹ãå£ããå Žåãç§ãã¡ã¯äœã®é²å±ãèŠãããã倧éã®è§£çŽãçã¿åºããŸããã ãã®åé¡ã§ã¯ãçŸåšã®åäœãããŸãæ©èœããã±ãŒã¹ã«ã€ããŠã¯è³ã«ããªãããšã«æ³šæããŠãã ããã ç§ãã¡ã¯ãããå£ããåŸã«ã®ã¿ããã«ã€ããŠèãã§ãããã
äŸãæãããšãçŸåšã®åäœã¯ãç§ãã¡ãããªãé·ãé調æ»ããŠãã宣èšåãã©ãŒã«ã¹ç®¡çã®ãŠãŒã¹ã±ãŒã¹ã«å®éã«åœ¹ç«ã¡ãŸãã ããŒã¿ã«ã§ããã«ããããããããã©ãŒã«ã¹/ãã©ãŒãããŒãããªãŒã«é¢ããŠã¢ãŒãã«ã®ãå
éšãã§çºçãããã®ãšããŠæ±ããšäŸ¿å©ã§ãã ãã®ã¹ã¬ããã§ææ¡ãããŠãããåçŽãªã createPortal(tree, boolean)
ææ¡ãåºè·ããå ŽåãããŒã¿ã«èªäœãå¿
èŠãªåäœããç¥ããããšãã§ããªãããããã®ãŠãŒã¹ã±ãŒã¹ã¯æ©èœããŸããã èãããã解決çãæ¢ãã«ã¯ãæ°åã®ãŠãŒã¹ã±ãŒã¹ãæ€èšããå¿
èŠãããããã®ãã¡ã®ããã€ãã¯ãŸã å®å
šã«ã¯ç解ãããŠããŸããã ããã¯ç¢ºãã«ããæç¹ã§è¡ãå¿
èŠããããŸããããããæ£ããè¡ãããã®å€å€§ãªæéã®ã³ãããã¡ã³ãã§ãããããããŸã§ã®ãšããç§ãã¡ã¯ããã«éäžããããšãã§ããŸããã§ããã
ç¹ã«ã€ãã³ãã¯åä»ãªé åã§ããããšãã°ãäœå¹Žã«ããããåé¡ã«å¯ŸåŠããããã«å€ãã®å€æŽãå ããã°ããã§ãããããã¯ä»å¹Žå€§ããªçŠç¹ãšãªã£ãŠããŸãã ããããäžåºŠã«ã§ããããšã¯ãããããããŸãã
äžè¬çã«ãç§ãã¡ã¯ããŒã ãšããŠãå€ãã®åé¡ãæµ ãããã®ã§ã¯ãªããããã€ãã®åé¡ã«æ·±ãçŠç¹ãåãããããšããŸãã æ®å¿µãªãããããã¯ãä»ã®éèŠãªã®ã£ãããä¿®æ£ããŠããæäžã§ããããåé¡ãå®å šã«è§£æ±ºãã代æ¿èšèšããªãããã«ãããã€ãã®æŠå¿µäžã®æ¬ é¥ãã®ã£ãããäœå¹Žãåããããªãå¯èœæ§ãããããšãæå³ããŸãã ç§ã¯ãããèãã®ãã€ã©ã€ã©ããããšãç¥ã£ãŠããŸãããããŠããã¯ç§ããã®ã¹ã¬ããããé¢ããçç±ã®äžéšã§ãã ä»ã®ããã€ãã®åæ§ã®ã¹ã¬ããã¯ãåé¡ãšèãããã解決çã®ããæ·±ã説æã«ãªããŸãããããã¯åœ¹ã«ç«ã¡ãŸãããããã¯äž»ã«ã+1ãã®æŽªæ°ŽãšãåçŽãªãä¿®æ£ã®ææ¡ã«ãªããŸããããã®ãããããã¯å°é£ã§ãããææ矩ã«ããã«åŸäºããã
ããã人ã ãèãããã£ãçãã§ã¯ãªãããšã¯ç¥ã£ãŠããŸããããŸã£ããçãããªãããã¯ãŸãã ãšæããŸãã
ææãã䟡å€ã®ãããã1ã€ã®ç¹ã¯ããã®ã¹ã¬ããã§èª¬æãããŠããåé¡ç¹ã®ããã€ãã¯ãä»ã®æ¹æ³ã§è§£æ±ºãããå¯èœæ§ããããšããããšã§ãã äŸãã°ïŒ
å ·äœçã«ã¯ãåæãã©ãŒã«ã¹ã€ãã³ãã§stopPropagationãåŒã³åºããŠãããŒã¿ã«ããã®ãããªã³ã°ãé²æ¢ãããšãïŒdocumentäžã®Reactã®ãã£ããã£ããããã³ãã©ãŒã®ãã€ãã£ããã©ãŒã«ã¹ã€ãã³ãã§ãstopPropagationãåŒã³åºãããŸããã€ãŸããäžã®å¥ã®ãã£ããã£ããããã³ãã©ãŒã«ã¯å°éããŸããã§ããã
Reactã¯ããããªã³ã°ããšãã¥ã¬ãŒãããããã«ãã£ããã£ãã§ãŒãºã䜿çšããªããªããããã¥ã¡ã³ãã®ã€ãã³ãããªãã¹ã³ããªããªããŸããã ãããã£ãŠããã©ã¹ãã¬ãŒã·ã§ã³ã解æ¶ããããšãªããä»ã®å€æŽãèæ ®ããŠããããŸã§ã«æçš¿ããããã¹ãŠã®ãã®ãåè©äŸ¡ããå¿ èŠããããŸãã
ãã€ãã£ãã€ãã³ãã¯ãŸã ããã«ã§ãããReactã³ãŒãã¯äž»ã«jQueryã¢ããªã±ãŒã·ã§ã³å ã§ãã¹ããããŠãããããã°ããŒãã«jQuerykeyDownãã³ãã©ãŒã¯
ãŸã ã€ãã³ããååŸããŸãã
åæ§ã«ãReact 17ã¯ã€ãã³ããã«ãŒããšããŒã¿ã«ã³ã³ããã«ã¢ã¿ããããŸãïŒãããŠå®éã«ã¯ãã®æç¹ã§ãã€ãã£ãã®äŒæãåæ¢ããŸãïŒã®ã§ãç§ã解決ãããããšãæåŸ ããŠããŸãã
renderSubtreeIntoContainer
åé€ã«é¢ãããã€ã³ãã«ã€ããŠã æåéãã ReactDOM.render
ãšã®å¯äžã®éãã¯ãã¬ã¬ã·ãŒã³ã³ããã¹ããäŒæããããšã§ãã renderSubtreeIntoContainer
ãå«ãŸãªããªãªãŒã¹ã«ã¯ãã¬ã¬ã·ãŒã³ã³ããã¹ããå«ãŸããªãããã ReactDOM.render
ã¯100ïŒ
åäžã®ä»£æ¿æ段ã®ãŸãŸã«ãªããŸãã ãã¡ãããããã¯ããåºãåé¡ã解決ãããã®ã§ã¯ãããŸãããã renderSubtree
ã«é¢ããæžå¿µã¯ç¹ã«èŠåœéãã ãšæããŸãã
@gaearon
renderSubtreeIntoContainer
åé€ã«é¢ãããã€ã³ãã«ã€ããŠã æåéããReactDOM.render
ãšã®å¯äžã®éãã¯ãã¬ã¬ã·ãŒã³ã³ããã¹ããäŒæããããšã§ããrenderSubtreeIntoContainer
ãå«ãŸãªããªãªãŒã¹ã«ã¯ãã¬ã¬ã·ãŒã³ã³ããã¹ããå«ãŸããªããããReactDOM.render
ã¯100ïŒ åäžã®ä»£æ¿æ段ã®ãŸãŸã«ãªããŸãã ãã¡ãããããã¯ããåºãåé¡ã解決ãããã®ã§ã¯ãããŸããããrenderSubtree
ã«é¢ããæžå¿µã¯ç¹ã«èŠåœéãã ãšæããŸãã
ããªããããã«ã€ããŠèšåããã®ã§ã以äžã®ã³ãŒãã¯ã€ãã³ããããªã³ã°ãªãã§ReactããŒã¿ã«ã®æå¹ã§å®å šãªå®è£ ã«ãªãã®ã ããããšæããŸãïŒ
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
ã¢ãã³ã³ã³ããã¹ããééãããªããšããåé¡ã¯ãŸã ãããŸãããããã¯æ°ããåé¡ã§ã¯ãããŸããïŒ renderSubtree
ã圱é¿ãåããŸãïŒã åé¿çã¯ãããªãŒãå€æ°ã®ã³ã³ããã¹ããããã€ããŒã§å²ãããšã§ãã å
šäœãšããŠãããªãŒããã¹ãããããšã¯çæ³çã§ã¯ãªããããã¬ã¬ã·ãŒã®æ¢åã®ã³ãŒãã·ããªãªä»¥å€ã§ã¯ããã®ãã¿ãŒã³ã«ç§»è¡ããããšã¯ãå§ãããŸããã
ç¹°ãè¿ãã«ãªããŸããã@ gaearonã®èšäºãããããšãããããŸããïŒ
å£ããã±ãŒã¹ã®ãªã¹ããšåé¿çïŒReact v17çšã«æŽæ°ïŒãéçŽããããšããã³ã¢ããŒã å€ã®èª°ãã«ãšã£ãŠæãçç£çãªãã®ã«ãªãããã§ãïŒééã£ãŠããå Žåã¯èšæ£ããŠãã ããïŒïŒã
ç§ã¯ä»åŸæ°é±éã§å§åãããŸãããã§ããã ãæ©ãããããšãç®æããŠããŸãã ä»ã®èª°ãã以åã«ãããè¡ãããšãã§ããå ŽåããŸãã¯ã¹ããããã§ãã£ã€ã ã鳎ãããå ŽåïŒ @diegohazãè¡ã£ãããã«ïŒãããã¯çŽ æŽãããããšã§ãïŒ
ã±ãŒã¹ã®ãªã¹ããéçŽããããšã¯ééããªã圹ã«ç«ã¡ãŸãããå£ããã±ãŒã¹ã ãã§ãªããçŸåšã®åäœãçã«ããªã£ãŠããã±ãŒã¹ãå«ããå¿ èŠããããšæããŸãã
è¿œå ãããããªãã¯ã¹ããŒã¹ãããå Žåã¯ãã¢ããªãšUIã©ã€ãã©ãªã®äœæè ã®äž¡æ¹ãããŠãŒã¹ã±ãŒã¹ãè¿œå ã§ããã°å¹žãã§ãã äžè¬çã«ãç§ã¯ãã³ã«åæããŸããããã¯æã ç ©ããããã®ã§ãããåé¿ããã®ã¯ç°¡åã§ãã Reactã®ãããªã³ã°ãå¿ èŠãªå Žåã¯ãReactã®å©ãããªããã°ã±ãŒã¹ãã«ããŒããã®ã¯éåžžã«å°é£ã§ãã
ã±ãŒã¹ã®ãªã¹ããéçŽããããšã¯ééããªã圹ã«ç«ã¡ãŸãããå£ããã±ãŒã¹ã ãã§ãªããçŸåšã®åäœãçã«ããªã£ãŠããã±ãŒã¹ãå«ããå¿ èŠããããšæããŸãã
誰ããããã«äŸåãããªãŒãã³ãœãŒã¹ã³ãŒã/æœåºã³ãŒããç§ã«ææã§ããã°ãããããå«ããŠåãã§ããŸãïŒ åã«è¿°ã¹ãããã«ãçŸåšã®åäœã«åé¡ããã人ã ãããã®åé¡ã«é¢äžããŠããã®ã§ãèŠã€ããã®ã¯å°ãé£ããã§ãð
è¿œå ãããããªãã¯ã¹ããŒã¹ãããå Žåã¯ãã¢ããªãšUIã©ã€ãã©ãªã®äœæè ã®äž¡æ¹ãããŠãŒã¹ã±ãŒã¹ãè¿œå ã§ããã°å¹žãã§ãã äžè¬çã«ãç§ã¯ãã³ã«åæããŸããããã¯æã ç ©ããããã®ã§ãããåé¿ããã®ã¯ç°¡åã§ãã Reactã®ãããªã³ã°ãå¿ èŠãªå Žåã¯ãReactã®å©ãããªããã°ã±ãŒã¹ãã«ããŒããã®ã¯éåžžã«å°é£ã§ãã
念é ã«çœ®ããŠããç¹å®ã®ã¹ããŒã¹ããŸãã¯ã±ãŒã¹ããšã«1ã€ã®ã³ãŒããµã³ãããã¯ã¹ïŒãŸãã¯jsfiddleãªã©ïŒãå ±æããããšã¯ãã¹ã¿ãŒã¿ãŒãšããŠæ©èœããŸããïŒ ããã€ãã®ã±ãŒã¹ãéããããããããã¹ãŠãã³ã³ãã€ã«ããŠã¿ãããšãã§ããŸãã
ããã§ã¹ã¬ãããéå§ããŸããïŒ https ïŒ
æãåèã«ãªãã³ã¡ã³ã
ããã§ãç§ã«ã¯äžå¿ èŠã«è€éã«æããŸãã ãªãã·ã§ã³ã®ããŒã«ãã©ã°ãcreatePortalã«è¿œå ããŠããããªã³ã°åäœããããã¯ã§ããããã«ããªãã®ã¯ãªãã§ããïŒ