场景
在日常的开发过程中,经常会遇到对网页进行事件监听的相关需求。如果不使用任何三方库,自己去做应该是这样子的:
const hello = () => console.log('world');
useEffect(() => {
window.addEventListener('click', hello);
return () => {
window.removeEventListener('click', hello);
};
});
需要在组件加载时,添加相关事件的监听;在组件被销毁时,卸载相关事件的监听。以此来提升相关页面的实际性能。
但是如果每个事件监听都这么做的话,会导致整体的代码冗余过多。
因此就需要对相关的代码封装hooks,方便后续的重复使用。
接下来笔者就为大家分析一下如何封装一个useEventListener的hooks,来在react中挂载相关监听事件。
实现
源码
useEventListener需要用户传入以下四个参数:
target:需要挂载监听事件的节点eventName:需要监听的事件名,如click、hashchange等listener:具体执行的监听函数options:监听的选项,具体内容可以参考:MDN-addEventListener
下面是该hooks的具体实现代码,代码后附有详细的解析:
export function useEventListener(target, eventName, listener, options) {
// ①
const storedListener = useRef(listener);
// ②
useEffect(() => {
storedListener.current = listener;
}, [listener]);
useEffect(() => {
// ③
const element = getTargetElement(target, window);
// ④
if (!element || !element?.addEventListener) return;
// ⑤
const eventListener = (event: any) => storedListener.current(event);
// ⑥
element.addEventListener(eventName, eventListener, options);
return () => {
// ⑦
element.removeEventListener(eventName, eventListener, options);
};
}, [eventName, target, options]);
}
①:创建了一个ref来存储用户传入的监听方法。
②:监听用户传入的监听方法,如果监听方法有改动,那么就实时更新当前存储的监听方法。
③:用户传入的需要监听的节点,可能是多种类型的,因此需要实现一个getTargetElement方法:
// 3-1 const isFunction = (value) => typeof value === 'function' const getTargetElement = (target, defaultElement) => { // 3-2 if (!target) { return defaultElement; } let targetElement; // 3-3 if (isFunction(target)) { targetElement = target(); // 3-4 } else if ('current' in target) { targetElement = target.current; } else { // 3-5 targetElement = target; } return targetElement; }
- 3-1:中实现了一个方法来判断当前传入的是否是一个
function- 3-2:如果target是一个非值,那么就直接采用默认的节点,挂载监听方法
- 3-3:如果用户传入的是一个方法,那么意味着需要执行该方法才能获取相关的节点,因此执行获取方法后返回该节点
- 3-4:如果用户传入的是一个
Ref,那么可以通过target.current来获取相关的节点- 3-5:默认情况下,返回传入的target节点
④:如果通过getTargetElement方法获取的节点是一个非值或者没有addEventListener方法,那么就不执行下面的操作。
⑤:包装一个事件监听方法eventListener,方便后续传入addEventListener及removeEventListener中。
⑥:对目标的元素添加事件监听方法,并传入用户指定的options参数。
⑦:在当前hooks被卸载时,清除目标元素中的事件监听方法。
至此我们就完成了useEventListenerhooks的封装。需要事件监听时,只需要引入该钩子即可搞定所有。
开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 18 天,点击查看活动详情