npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@chroma-x/react-custom-dom-events

v1.1.4

Published

Easily integrate custom DOM events in React functional components

Downloads

13

Readme

react-custom-dom-events

Easily integrate custom DOM events in React functional components

This project is a continuation of react-custom-events.

Motivation

There are situations in which the React callback prop handling makes it impossible or at least unconvenient to handle user interactions.

Common practice is to map user interactions to context or even worse to global state change that then acts as some kind of event provider or broadcaster. This could work for most cases, but it introduces strict dependencies between components their environment. Especially in situations in which you have no knowledge about the surrounding of the ui components – like ui library development – a generic and self contained solution could be required.

Using native custom DOM events could be the better choice because components usually are already depending on the existance of the DOM and they allow making use of the native behavior of DOM events like bubbling and such.

This way you can easily orchestrate event emitting and event listening components – even if there are multiple emitters or multiple listeners which is hard to manage if you rely on a single context or global store to broadcast your state changes.

React current state

The way of React handling "events" is to pass callbacks to child components via properties. That leads to drilling callback props through the component hirarchie whether the components on the route down the hirarchie should have knowledge about these props or not. This is often avoided by using Context which could lead to unwanted complexity. Especially if you can not provide the context as a part of your ui component but rely on the existance of a specific context provider in the application that utilizes your components you introduce a dependency that you can not count on.

Another problem is that you often need to write callback functions that acts as some kind of orchestrator to then call different other functions to resolve user interactions on multiple components. This results in unwanted coupling bewteen components and extra complexity for handling the callback composition.

To avoid all this, you can use custom DOM events, that could be emitted by any component and other components can listen on. They could bubble through the DOM tree – which usually represents your component hirarchie – and can be handled on different levels.

So the handling and orchestration is already provided by the native behavior of custom DOM events. No need to reinvent the logic behind that.

How to use

Installation

npm i @chroma-x/react-custom-dom-events

Event emission

The emitting element could be a RefObject<HTMLElement>, MutableRefObject<HTMLElement> or a HTMLElement.

import { useRef } from 'react';
import { emitCustomDomEvent } from '@chroma-x/react-custom-dom-events';

const emittingElement = useRef(null);

const handleClick = (): void => {
  emitCustomDomEvent(emittingElement, 'myCustomEvent');
};

return (
  <button ref={emittingElement} onClick={handleClick}>Emit custom event</button>
);

Attach payload to the event

emitCustomDomEvent<string>(emittingElement, 'myCustomEvent', 'Event payload');

Custom event options

emitCustomEvent<string>(emittingElement, 'myCustomEvent', 'Event payload', {
  bubbles: true,
  cancelable: true, 
  composed: true
});

Event listening

The listening element could be a RefObject<HTMLElement>, MutableRefObject<HTMLElement> or a HTMLElement.

The provided callback is called with a native custom event of which you can use the common features like preventing the default behavior and so on. The payload is as usual part of the event as the member detail.

import { useRef } from 'react';
import { useCustomDomEventListener } from '@chroma-x/react-custom-dom-events';

const listenerElement = useRef(null);

useCustomDomEventListener<string>(listenerElement, 'myCustomEvent', (event): void => {
  event.stopPropagation();
  console.debug(event.detail);
});

return (
  <div ref ={listenerElement} />
);

useCustomDomEventListener returns a closure that allows you to remove the added event listener if required.

import { useRef } from 'react';
import { useCustomDomEventListener } from '@chroma-x/react-custom-dom-events';

const listenerElement = useRef(null);

const removeListener = useCustomDomEventListener<string>(listenerElement, 'myCustomEvent', (event): void => {
  event.stopPropagation();
  console.debug(event.detail);
});

const handleClick = (): void => {
  removeListener();
};

return (
  <div ref={listenerElement}>
    <button onClick={handleClick}>Remove event listener</button>
  </div>
);

useCustomDomEventListener makes use of the useEffect hook, so it can be used in functional components only.

There is no need to handle the removal of the event listener. Listeners are removed on component unmount by reacts useEffect destructor.