【发布时间】:2019-12-05 06:15:04
【问题描述】:
我在 React 中创建了一个自定义钩子,它为给定的一组事件设置了一个事件监听器。存在一组默认事件,并且此自定义钩子的使用者预计不会在大多数用例中自定义这些事件。通常,我希望在安装组件时添加事件侦听器,并在卸载组件时将其删除。然而,坚持钩子的原则(和eslint(react-hooks/exhaustive-deps) lint 规则),我希望优雅地处理对要观察的事件列表的更改。使用 React 钩子实现此目的最惯用的方法是什么?
假设我只想删除所有事件侦听器并在事件列表更改时重新添加它们,我可以尝试以下操作:
const useEventWatcher = (
interval = 5000,
events = ['mousemove', 'keydown', 'wheel']
) => {
const timerIdRef = useRef();
useEffect(() => {
const resetInterval = () => {
if (timerIdRef.current) {
clearInterval(timerIdRef.current);
}
timerIdRef.current = setInterval(() => {
console.log(`${interval} milliseconds passed with no ${events.join(', ')} events!`);
}, interval)
};
events.forEach(event => window.addEventListener(event, resetInterval));
// Don't want to miss the first time the interval passes without
// the given events triggering (cannot run the effect after every render due to this!)
resetInterval();
return () => {
events.forEach(event => window.removeEventListener(event, resetInterval));
};
}, [events, interval]);
}
很遗憾,这将无法按预期运行。请注意,我想为events 参数提供一个默认值。使用当前方法执行此操作意味着 events 每次自定义挂钩运行时都指向不同的引用,这意味着效果每次也运行(由于浅层依赖比较)。理想情况下,我想要一种效果取决于数组内容而不是引用的方法。实现这一目标的最佳方法是什么?
【问题讨论】:
-
为什么要避免在部门中列出
events?如果用户最终想要指定事件,那么将['scroll']更改为['click']处理错误事件可能会令人大吃一惊。免费处理这样的案子不是更好吗? -
查看我的编辑以获得澄清。
标签: reactjs react-hooks use-effect