我正在创建一个自定义钩子来检测给定HTMLElement
内部/外部的单击。
由于钩子接受函数作为参数,因此似乎需要将输入包装在useCallback
中,或者用useRef
存储在钩子中,以防止useEffect
重复触发。
以下两种方法在功能上是否都是相同的?
方法1(首选)
// CALLER
useClickInsideOutside({
htmlElement: htmlRef.current,
onClickOutside: () => {
// Do something via anonymous function
},
});
// HOOK
const useClickInsideOutside = ({
htmlElement,
onClickOutside,
}) => {
const onClickOutsideRef = useRef(onClickOutside);
onClickOutsideRef.current = onClickOutside;
useEffect(() => {
function handleClick(event) {
if (htmlElement && !htmlElement.contains(event.target)) {
onClickOutsideRef.current && onClickOutsideRef.current();
}
}
document.addEventListener(MOUSE_DOWN, handleClick);
return () => { document.removeEventListener(MOUSE_DOWN, handleClick); };
}, [htmlElement]);
}
方法二
// CALLER
const onClickOutside = useCallback(() => {
// Do something via memoized callback
}, []);
useClickInsideOutside({
htmlElement: htmlRef.current,
onClickOutside,
});
// HOOK
const useClickInsideOutside = ({
htmlElement,
onClickOutside,
}) => {
useEffect(() => {
function handleClick(event) {
if (htmlElement && !htmlElement.contains(event.target)) {
onClickOutside();
}
}
document.addEventListener(MOUSE_DOWN, handleClick);
return () => { document.removeEventListener(MOUSE_DOWN, handleClick); };
}, [htmlElement, onClickOutside]);
}
第一个(我更喜欢它,因为它似乎使钩子更容易使用/依赖较少的假设)像我想象的那样工作吗?或者useEffect
可能会在handleClick
中封装陈旧的函数引用。
发布于 2020-09-02 11:51:48
useCallback
是解决这一问题的正确方法。然而,我认为我在设计它的时候,我可以把备忘录从消费者那里抽象出来:
/**
* @param {MutableRefObject<HTMLElement>} ref
* @param {Function} onClickOutside
*/
const useClickInsideOutside = (ref, onClickOutside) => {
const { current: htmlElement } = ref;
const onClick = useCallback((e) => {
if (htmlElement && !htmlElement.contains(e.target)) {
onClickOutside();
}
}, [htmlElement, onClickOutside])
useEffect(() => {
document.addEventListener(MOUSE_DOWN, onClick);
return () => document.removeEventListener(MOUSE_DOWN, onClick);;
}, [onClick]);
}
由于我已经谈到了设计,所以我会尝试使设计类似于类似的API函数,其中两个参数是间接相关的。我最终会变成这样:
// Consumer component
const ref = useRef()
useClickOutside(ref, () => {
// do stuff in here
})
https://stackoverflow.com/questions/63712538
复制