Skip to content

useEvent

作用

监听事件

使用

ts
import { useEvent, useList } from 'react-use'

const Demo = () => {
  const [list, { push, clear }] = useList()

  const onKeyDown = useCallback(({ key }) => {
    if (key === 'r') clear()
    push(key)
  }, [])

  useEvent('keydown', onKeyDown)

  return (
    <div>
      <p>
        Press some keys on your keyboard, <code style={{ color: 'tomato' }}>r</code> key resets the
        list
      </p>
      <pre>{JSON.stringify(list, null, 4)}</pre>
    </div>
  )
}

源码

ts
import { useEffect } from 'react'
import { isBrowser, off, on } from './misc/util'

export interface ListenerType1 {
  addEventListener(name: string, handler: (event?: any) => void, ...args: any[])

  removeEventListener(name: string, handler: (event?: any) => void, ...args: any[])
}

export interface ListenerType2 {
  on(name: string, handler: (event?: any) => void, ...args: any[])

  off(name: string, handler: (event?: any) => void, ...args: any[])
}

// 事件添加接口类型
export type UseEventTarget = ListenerType1 | ListenerType2

const defaultTarget = isBrowser ? window : null

const isListenerType1 = (target: any): target is ListenerType1 => {
  return !!target.addEventListener
}
const isListenerType2 = (target: any): target is ListenerType2 => {
  return !!target.on
}

// 添加监听事件的方式
type AddEventListener<T> = T extends ListenerType1
  ? T['addEventListener']
  : T extends ListenerType2
  ? T['on']
  : never

export type UseEventOptions<T> = Parameters<AddEventListener<T>>[2]

const useEvent = <T extends UseEventTarget>(
  // 事件名称
  name: Parameters<AddEventListener<T>>[0],
  // 事件触发的函数
  handler?: null | undefined | Parameters<AddEventListener<T>>[1],
  target: null | T | Window = defaultTarget,
  // 配置项
  options?: UseEventOptions<T>
) => {
  useEffect(() => {
    if (!handler) {
      return
    }
    if (!target) {
      return
    }
    // 判断以哪种方式添加事件
    if (isListenerType1(target)) {
      on(target, name, handler, options)
    } else if (isListenerType2(target)) {
      target.on(name, handler, options)
    }
    // 卸载移除事件监听
    return () => {
      if (isListenerType1(target)) {
        off(target, name, handler, options)
      } else if (isListenerType2(target)) {
        target.off(name, handler, options)
      }
    }
  }, [name, handler, target, JSON.stringify(options)])
}

export default useEvent

如有转载或 CV 的请标注本站原文地址