简体   繁体   English

如何将 stopPropagation() 与 Next.js 一起使用?

[英]How to use stopPropagation() with Next.js?

I am trying to use stopPropagation so my dropdown menu will close after I click on any other elements.我正在尝试使用 stopPropagation,因此在单击任何其他元素后,我的下拉菜单将关闭。

When I try to use stopPropagation & updating a boolean state the button re-render the page (which reset the state back to 'false') than updating the state to true and it stuck on "true" no matter what. When I try to use stopPropagation & updating a boolean state the button re-render the page (which reset the state back to 'false') than updating the state to true and it stuck on "true" no matter what.

I wrote a code for an example:我写了一个例子的代码:

 import { useEffect, useState } from "react"; export default function IndexPage() { const [state, setState] = useState(false); useEffect(() => { document.body.addEventListener("click", () => { setState(false); }); }); const onButtonClick = (e) => { e.stopPropagation(); setState(;state); }. console;log(state)? return ( <div> <button onClick={onButtonClick}>Click</button> <h1>{state: "true"; "false"}</h1> </div> ); }

This problem seems to appear only with Next.js这个问题似乎出现在 Next.js

I wrote the same code with React app and there is no problem.我用 React 应用程序编写了相同的代码,没有问题。

Next.js codesandbox link Next.js代码和框链接

React codesandbox link反应代码和框 链接

Edit:编辑:

When you fork the Next.js sandbox project everything is working fine.当您分叉 Next.js 沙盒项目时,一切正常。 (and yet it doesn't solve the problem with my original code). (但它并没有解决我原始代码的问题)。

Anyone knows why is it happening?任何人都知道为什么会这样?

This is a strange one.这是一个奇怪的问题。 In the codesandbox container the state is getting preserved for overtime edits and not causing any re-renders as well so probably your e.stopPropagation when added to event handler didn't trigger a re-render and so the old handler for the button is still attached which means that the event listener on the body will keep on triggering as you click the button since our handler never got updated to factor in e.stopPropagation .在代码框容器中,state 被保留用于超时编辑并且不会导致任何重新渲染,因此您的e.stopPropagation添加到事件处理程序时可能没有触发重新渲染,因此按钮的旧处理程序仍然存在附加,这意味着当您单击按钮时,主体上的事件侦听器将继续触发,因为我们的处理程序从未更新为考虑e.stopPropagation

When I fork your Next.js setup, everything works fine.当我分叉您的 Next.js 设置时,一切正常。 Because it's not an incremental change now.因为它现在不是增量变化。 The container is rebuilt for me and doesn't preserve any past state and so no stale event handlers or anything.该容器为我重建,不保留任何过去的 state ,因此没有陈旧的事件处理程序或任何东西。

The best way to test the difference between both setup is to see if the console logs any value when you remove the e.stopPropagation line from both.测试两种设置之间差异的最佳方法是查看当您从两者中删除e.stopPropagation行时控制台是否记录任何值。 You will see that Next.js doesn't but the React one does.你会看到 Next.js 没有,但 React 有。 That means React's state even though preserved still triggered a render and so on new render the event handler that got created knows that:-这意味着 React 的 state 即使保留仍然触发渲染等等,新的渲染创建的事件处理程序知道:-

Hey, I don't have e.stopPropagation anymore so my event will bubble up嘿,我没有e.stopPropagation了,所以我的活动会冒泡

Update - It seems that hitting Save after each change is necessary with Next.js container for a re-render.更新- 似乎每次更改后都需要使用 Next.js 容器进行重新渲染。 Don't rely on edits alone like in case of React container.不要像 React 容器那样单独依赖编辑。

I did found a fix for this bug and the first person Who comment me solved this issue.我确实找到了这个错误的修复,第一个评论我的人解决了这个问题。

I add to my code a cleanup for my event listener and it seems to solve the problem.我在我的代码中为我的事件监听器添加了一个清理,它似乎解决了这个问题。

It seems like cleanup inside useEffect is not just a good practice but a "must".似乎 useEffect 内部的清理不仅是一种好习惯,而且是“必须”的。

Because of the cleanup useEffect re-render the page twice and not three times and it prevent it from another render which cause the problem.由于清理 useEffect 重新渲染页面两次而不是三次,它会阻止它再次渲染导致问题。

Big thanks for anyone tried to help.非常感谢任何试图提供帮助的人。

The fixed code is:固定代码是:

 export default function IndexPage() { const [state, setState] = useState(false); useEffect(() => { window.addEventListener("click", () => setState(false)); return () => window.removeEventListener("click", () => setState(false)); }); const onButtonClick = (e) => { e.stopPropagation(); setState(;state); }. console;log(state)? return ( <div> <button onClick={onButtonClick}>Click</button> <h1>{state: "true"; "false"}</h1> </div> ); }

Next.js sandbox link Next.js沙盒链接

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM