475

useEventListener

Hook that attaches an event listener to the specified target

browsernecessarytest coverage
Score000
import { useEventListener } from '@siberiacancode/reactuse';
import { useState } from 'react';

const VARIANTS = [
  { size: 24, points: 3 },
  { size: 36, points: 2 },
  { size: 52, points: 1 }
];

const PADDING = 16;

const Demo = () => {
  const [target, setTarget] = useState({ x: 100, y: 100, size: 36, points: 2 });
  const [score, setScore] = useState(0);

  const containerRef = useEventListener<HTMLDivElement>('click', (event) => {
    if (!(event.target as HTMLElement).dataset.target) return;

    const container = containerRef.current;
    if (!container) return;

    setScore((value) => value + target.points);

    const rect = container.getBoundingClientRect();
    const next = VARIANTS[Math.floor(Math.random() * VARIANTS.length)];
    const x = PADDING + Math.random() * (rect.width - next.size - PADDING * 2);
    const y = PADDING + Math.random() * (rect.height - next.size - PADDING * 2);

    setTarget({ x, y, ...next });
  });

  return (
    <section className='demo-ui flex w-full max-w-2xl flex-col p-4'>
      <div
        ref={containerRef}
        className='border-border bg-card relative h-[320px] w-full cursor-crosshair overflow-hidden rounded-xl border shadow-sm select-none'
      >
        <div className='pointer-events-none absolute top-3 right-3 z-10 flex items-baseline gap-1.5 font-mono tabular-nums'>
          <span className='text-muted-foreground text-[10px] tracking-[0.15em] uppercase'>
            Score
          </span>
          <span className='text-foreground text-sm font-semibold'>
            {String(score).padStart(3, '0')}
          </span>
        </div>

        <div
          style={{
            left: target.x,
            top: target.y,
            width: target.size,
            height: target.size
          }}
          className='bg-foreground absolute rounded-full shadow-lg'
          data-target='true'
        />
      </div>
    </section>
  );
};

export default Demo;

Installation

pnpm add @siberiacancode/reactuse

Usage

useEventListener(ref, 'click', () => console.log('click'));
// or
const ref = useEventListener('click', () => console.log('click'));

Type Declarations

import type { HookTarget } from '@/utils/helpers';

import type { StateRef } from '../useRefState/useRefState';

export type UseEventListenerOptions = {
  enabled?: boolean;
} & AddEventListenerOptions;

export type UseEventListenerReturn<Target extends Element> = StateRef<Target>;

export interface UseEventListener {
  <Event extends keyof WindowEventMap = keyof WindowEventMap>(
    target: HookTarget,
    event: Event,
    listener: (this: Window, event: WindowEventMap[Event]) => void,
    options?: UseEventListenerOptions
  ): void;

  <Event extends keyof DocumentEventMap = keyof DocumentEventMap>(
    target: HookTarget,
    event: Event,
    listener: (this: Document, event: DocumentEventMap[Event]) => void,
    options?: UseEventListenerOptions
  ): void;

  <Event extends keyof HTMLElementEventMap = keyof HTMLElementEventMap>(
    target: HookTarget,
    event: Event,
    listener: (this: Element, event: HTMLElementEventMap[Event]) => void,
    options?: UseEventListenerOptions
  ): void;

  <Target extends Element, Event extends keyof HTMLElementEventMap = keyof HTMLElementEventMap>(
    event: Event,
    listener: (this: Target, event: HTMLElementEventMap[Event]) => void,
    options?: UseEventListenerOptions,
    target?: never
  ): UseEventListenerReturn<Target>;

  <
    Target extends Element,
    Event extends keyof MediaQueryListEventMap = keyof MediaQueryListEventMap
  >(
    event: Event,
    listener: (this: Target, event: MediaQueryListEventMap[Event]) => void,
    options?: UseEventListenerOptions,
    target?: never
  ): UseEventListenerReturn<Target>;
}

API

Parameters

NameTypeDefaultNote
targetHookTarget-The target element to attach the event listener to
eventEvent | Event[]-An array of event types to listen for
handler(this: Target, event: HTMLElementEventMap[Event]) => void-The event handler function
optionsUseEventListenerOptions-Options for the event listener

Parameters

NameTypeDefaultNote
eventEvent | Event[]-An array of event types to listen for
handler(this: Target, event: HTMLElementEventMap[Event] | MediaQueryListEventMap[Event]) => void-The event handler function
optionsUseEventListenerOptions-Options for the event listener

Returns

UseEventListenerReturn<Target>

Contributors

ddebabin

Last updated on