Closed cl1107 closed 6 months ago
感谢你的反馈,排查的情况是这样的:
document
上的 click
事件,因为阻止了冒泡,所以导致没有触发 clickAway 回调函数document
上的 mousedown
和 touchstart
事件,所以阻止冒泡也不会影响 clickAway 回调函数的触发我们可能需要讨论下是否要针对这一情况处理呢 @brickspert @crazylxr 我的想法是这样的:
mousedown
或者 touchstart
事件,我们就能兼容开发者在 click
下阻止冒泡,因为大多数情况下用 click
多于 mousedown
或者 touchstart
事件各有一些优点和缺点,需要讨论看一下哈
@cl1107 欢迎提出你的想法💡
上面的情况是在 react17 之后的,react17 之后,事件默认绑定在了根元素 #root
上,所以阻止冒泡直接不触发 document
上的 click
事件。
在 react17 以前,react 默认绑定事件在 document
上,即使阻止了冒泡也还是会触发 document
上的 click
事件。
在这个例子中,所以无论怎么点击 CodeSandbox文字
都不会显示 foobar
。因为点击触发更新,重新渲染,visible
变为 true,此时调用 clickAway 回调函数,始终获取到最新的 visible
,即为 true,又将 visible
变为 false。
这个情况下我认为 ahooks 是合理的,因为 CodeSandbox文字
是在 foobar
之外的,也触发了 clickAway 事件,visible
变为 false 也是合情理的
可以这两个例子: react16.8.6 react18.0.0
最终我的建议是: 更改默认事件
click
为mousedown
和touchstart
我感觉改成mousedown和touchstart的效果更符合预期,点击第二个CodeSandbox文字,对于第一个CodeSandbox而言就是clickAway了,应该是要触发第一个的clickAway的回调函数的
是的,不过默认如果改成了 mousedown
的话,有一个缺点就是在 mousedown
阻止冒泡的话和现在的 click
一样有问题的,只是说 mousedown
可能用的稍微少一点,所以默认事件建议改成 mousedown
遇到类似问题,useClickAway 绑定的元素(假设为Parent)中的子元素(假设为Child1)如果销毁了,并且产生了其他的子元素(假设为Child2),点击Child2也会触发useClickAway。 导致现在只能修改监听事件或者阻止子元素冒泡
遇到类似问题。
如果在 Modal 上使用 useClickAway
的话:
click
导致 Modal 根本打不开。(打开那一下点击也被算作了 "clickAway",于是 Modal 马上被关闭)mousedown
则一切正常。楼主的使用方式,违背了 useClickAway 的设计用途:“监听目标元素外的点击事件”。
请考虑把不想触发 useClickAway 的元素放在 ref 引用的 dom 范围里(可以解决楼主在线 demo 里的问题):
+ <div ref={ref1} style={{ height: 100 }}>
<div
onClick={(e) => {
e.stopPropagation();
console.log("CodeSandbox");
setVisible(true);
}}
>
CodeSandbox
</div>
- <div ref={ref1} style={{ display: visible ? "block" : "none" }}>
+ <div style={{ display: visible ? "block" : "none" }}>
foobar
</div>
</div>
复现链接:https://codesandbox.io/s/ahooks-clickaway-bug-v5t3zp?file=/src/App.js
这是使用react-use时的效果 https://user-images.githubusercontent.com/21985353/170660093-99cc3097-0ad9-45fa-866e-f8ab404aaf7a.mov
这是使用ahooks时的效果 https://user-images.githubusercontent.com/21985353/170660185-3abb028c-d082-4c59-8fda-46993ebbfd5a.mov