react Bug: 将窗口作为新的门户将破坏事件委托

5fjcxozz  于 5个月前  发布在  React
关注(0)|答案(4)|浏览(62)

React版本:任意?

重现步骤

  1. 将按钮附加到一个使用window.open打开的窗口门户上。
  2. 事件未触发
    链接到代码示例:
const { useState, useEffect } = React;

function WindowPortal({ children }) {
  const [container, setContainer] = useState(document.createElement('div'));
  useEffect(() => { 
    const newWindow = window.open('', '', 'width=600,height=400,left=200,top=200');
    newWindow.document.body.appendChild(container);
  });
  return ReactDOM.createPortal(children, container);
}
function App() {
  const [value, setValue] = useState('unclicked');
  const handleClick = () => setValue('clicked'); 
  return (
    <div>
      <div>Portal Test</div>
      <WindowPortal>
        <button onClick={handleClick}>{value}</button>
      </WindowPortal>
    </div>
  );
}

ReactDOM.render(
  React.createElement(App),
  document.getElementById('root')
);

由于所有事件都绑定到原始窗口,因此新窗口中的任何事件都不会被触发。我认为如果有意义的话,React可以支持一种新的模式来使用原生事件绑定,而不是事件委托。Preact实际上使用了原生浏览器事件,而不是React事件委托系统。

当前行为

新窗口中的组件事件未触发

预期行为

事件将被触发

iq3niunx

iq3niunx1#

你可以通过使用效果并将事件监听器附加到按钮上来实现它:

function WindowPortal({ children }) {
  const [container, setContainer] = useState(document.createElement("div"));

  useEffect(() => {
    const newWindow = window.open(
      "",
      "",
      "width=600,height=400,left=200,top=200"
    );
    newWindow.document.body.appendChild(container);
  }, [container]);

  return ReactDOM.createPortal(children, container);
}

export default function App() {
  const [value, setValue] = useState("unclicked");
  const buttonRef = useRef(null);
  const handleClick = () => setValue("clicked");

  useEffect(() => {
    if (buttonRef.current) {
      buttonRef.current.addEventListener("click", handleClick);

      return () => buttonRef.current.removeEventListener("click", handleClick);
    }
  });

  return (
    <div>
      <div>Portal Test</div>
      <WindowPortal>
        <button ref={buttonRef}>{value}</button>
      </WindowPortal>
    </div>
  );
}

看起来像是要变成一个漂亮的自定义钩子?

ne5o7dgx

ne5o7dgx2#

也许为了官方支持,我们可以引入新的事件属性,例如 nativeOnClick ?

ars1skjm

ars1skjm3#

@tombrowndev 是的,这应该可以工作。但是我不知道混合事件委托系统和任意引用事件绑定是否存在潜在问题。我觉得整个应用程序应该要么使用原生事件绑定,要么使用事件委托,而不是将一些事件委托给根元素,而另一些绑定到宿主DOM。

dwbf0jvd

dwbf0jvd4#

我们过去曾就事件传播和门户进行过几次讨论(参见#11387)。这似乎是那次讨论的一部分。

相关问题