ahooks源码分析-useEventListener

713 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第2天,点击查看活动详情

今天开始一起学习分享 ahooks 的源码

ahooks是阿里巴巴出品的一套高质量可靠的 React Hooks 库

今天分享 第2个 hooks- useEventListener

useEventListener

首先看下 useEventListener 的作用是什么

useEventListener的作用是优雅的使用 JavaScript中的 addEventListener。

接下来 看下 API

API

useEventListener(
  eventName: string,
  handler: (ev: Event) => void,
  options?: Options,
);

Params

参数说明类型默认值
eventName事件名称string-
handler处理函数(ev: Event) => void-
options设置(可选)Options-

一共有3个参数

eventName:事件名称

handler: 事件函数

options:可选的参数

再看下 可选的 参数

Options

参数说明类型默认值
targetDOM 节点或者 ref(() => Element) | Element | React.MutableRefObject<Element> | Window | Documentwindow
capture可选项,listener 会在该类型的事件捕获阶段传播到该 EventTarget 时触发。booleanfalse
once可选项,listener 在添加之后最多只调用一次。如果是 true,listener 会在其被调用之后自动移除。booleanfalse
passive可选项,设置为 true 时,表示 listener 永远不会调用 preventDefault() 。如果 listener 仍然调用了这个函数,客户端将会忽略它并抛出一个控制台警告。booleanfalse

接下来 看下 用法

基本用法

当点击的时候 数字 加 1

import React, { useState, useRef } from 'react';
import { useEventListener } from 'ahooks';

export default () => {
  const [value, setValue] = useState(0);
  const ref = useRef(null);

  useEventListener(
    'click',
    () => {
      setValue(value + 1);
    },
    { target: ref },
  );

  return (
    <button ref={ref} type="button">
      You click {value} times
    </button>
  );
};

image.png

监听 keydown 事件

监听 键盘 事件

import React, { useState } from 'react';
import { useEventListener } from 'ahooks';

export default () => {
  const [value, setValue] = useState('');

  useEventListener('keydown', (ev) => {
    setValue(ev.code);
  });

  return <p>Your press key is {value}</p>;
};

image.png

接下来 看下 源码

源码

首先看下接口参数的定义

type Options<T extends Target = Target> = {
  target?: T;
  capture?: boolean;
  once?: boolean;
  passive?: boolean;
};

第一个是target,是可选的,接口定义是Target,接着再看下 Target的定义

export type Target = BasicTarget<HTMLElement | Element | Window | Document>;

这里定义了 target 可能是 上面这几种类型

另外3个参数都是可选的布尔值

capture?: boolean;
  once?: boolean;
  passive?: boolean;

接着 按照 target各种值的类型,使用多态编写 各种情形

function useEventListener<K extends keyof HTMLElementEventMap>(
  eventName: K,
  handler: (ev: HTMLElementEventMap[K]) => void,
  options?: Options<HTMLElement>,
): void;
function useEventListener<K extends keyof ElementEventMap>(
  eventName: K,
  handler: (ev: ElementEventMap[K]) => void,
  options?: Options<Element>,
): void;
function useEventListener<K extends keyof DocumentEventMap>(
  eventName: K,
  handler: (ev: DocumentEventMap[K]) => void,
  options?: Options<Document>,
): void;
function useEventListener<K extends keyof WindowEventMap>(
  eventName: K,
  handler: (ev: WindowEventMap[K]) => void,
  options?: Options<Window>,
): void;
function useEventListener(eventName: string, handler: noop, options: Options): void;

最后使用一个来编写逻辑

首先使用 useLatest Hooks 将 传入的 函数 包装起来,返回最新的handler

const handlerRef = useLatest(handler);

然后将 传入的 target 作为参数 传入getTargetElement方法中,最后返回目标dom

const targetElement = getTargetElement(options.target, window);
      if (!targetElement?.addEventListener) {
        return;
      }

监听的事件函数 通过 handlerRef 来返回

const eventListener = (event: Event) => {
        return handlerRef.current(event);
      };

最后利用 js中提供的addEventListener和removeEventListener来监听事件函数和销毁事件函数

targetElement.addEventListener(eventName, eventListener, {
        capture: options.capture,
        once: options.once,
        passive: options.passive,
      });

      return () => {
        targetElement.removeEventListener(eventName, eventListener, {
          capture: options.capture,
        });
      };