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

react-event-forwarder

v1.0.1

Published

A small React library to dispatch and forward React and custom events end emit values, inspired by Svelte's createEventDispatcher and Vue's $emit

Downloads

22

Readme

react-event-forwarder

A small React library to dispatch and forward React and custom events and emit values, inspired by Svelte's createEventDispatcher and Vue's $emit

NPM JavaScript Style Guide

Install

npm install --save react-event-forwarder

Event-forwarding for truly independent components

Besides requiring some boilerplate code, lifting the state up in React creates a very special relation of dependence between the parent component and its/their child/ren. Because of this entanglement, changing the state, or the business logic of one component, often entails having to re-think the logic of the other.

The aim of react-event-forwarder is to allow child components to dispatch and emit custom events (which can carry a specific data payload), or to expose/forward React events to their direct ancestor, allowing you to get rid of state-lifting constraints and create truly independent and re-usable components while remaining faithful to the single source of truth principle.

How it works

This library is heavily inspired by Svelte's createEventDispatcher, and Vue's $emit. react-event-forwarder provides you with 3 alternatives to create an eventForwarders, depending on whether you prefer working with hooks, class components, or HOCs. It is a convention to assign the provided eventForwarder to a function or method and name it forwardEvt (except when working with the HOC, which will directly pass a prop with such name). forwardEvt takes a mandatory first argument, evt, which is either a string or an Event, and a second optional argument evtDetail, that can be any kind of variable. If you want to dispatch and forward a custom event, you shall pass a string representing the event name, and, if needed, and an optional payload. react-event-forwarder will create a Custom Event for you (FYI, the custom event won't bubble). You can now simply call it from the Parent, as you would with a normal event (on+ EventName in Pascal case). The payload will be stored in event.detail.

//Child, consumes forwardEvt from HOC
import { withCreateEvtForwarder } from 'react-event-forwarder'

const Child = ({ forwardEvt }) => {
    return (
        <div>
            <button
                onClick={() => forwardEvt('message', {msg: 'we are sending you a message'} )}
            >
                send message
            </button>
        </div>
    )
}

export default withCreateEvtForwarder(Child)

// Parent component

const Parent = props => {
    // ...business logic of the component
    return <Child onMessage={e => console.log(e.detail.msg)} />
}

If you want to forward a React event, or a custom one dispatched from a direct child, just pass eventForwarder to the event listener: it will automatically recognize the event and expose it to the parent as it is (no additional event is created).

//Child, consumes forwardEvt from HOC
import { withCreateEvtForwarder } from 'react-event-forwarder'

const Child = props => {
    return (
        <div>
            <input
                onInput={forwardEvt}
            />
        </div>
    )
}

export default withCreateEvtForwarder(Child)

// Parent component

const Parent = props => {
    // ...business logic of the component
    return <Child onInput={e => doStuff(e.target.value)}>
}

On top of this, and differently from Svelte and Vue, react-event-forwarder, always returns a Promise, allowing you to chain further actions and events at the complition of the event's callback.

More info on this async functionality below.

Hook

If you are working with funcitonal components, react-event-forwarder the easiest way to create an event forwarder is using the useCreateEventForwarder hook. This hook takes the component props as argument, and returns an event-forwarder function. It is good practice to name this return value forwardEvt.

You only need to create one forwardEvt function per component, which you can use to forward as many custom or React events as you like from that component. You can then use it in handler functions, or directly call it in the JSX. The hook needs to observe the props of the components, to extract the callbacks, so you have to destructure them only inside the component.

If you need to memoized it with useCallback, don't forget to watch for changes in props.

//Child
import { useEvtForwarder } from 'react-event-forwarder'

export const Child = props => {
    const forwardEvt = useEvtForwarder(props)
    
    return (
        <div>
            <button
                onClick={() => forwardEvt('message', {msg: 'we are sending you a message'} )}
            >
                send message
            </button>
        </div>
    )
}

// Parent component

const Parent = props => {
    // ...business logic of the compoent
    return <Child onMessage={e => console.log(e.detail.msg)} />
}

createEvtForwarder for class components

react-event-forwarder provides you with an API, createEventForwarder, which returns an event forwarder to be used directly in class components. You only need to call it inside your component and assign the return value to a method. Differently from the corresponding hook, createEventForwarder doesn't take any argument; the resutling forwardEvt function, however, works the same way.

//Child
import { createEvtForwarder } from 'react-event-forwarder'

export default class ClassChild extends Component {
    forwardEvt = createEvtForwarder()

    render() {
        return (
            <button onClick={() => this.forwardEvt('message', {msg: 'we are sending you a message'} )}>
                Send a message
            </button>
        )
    }
}

// Parent component

class Parent extends Component {
    // ...business logic of the compoent
    render () {
        return <Child onMessage={e => this.doStuff(e.detail.msg)} />
    }
}

HOC for both function and class Components

Finally, if you are working in a mixed environment, you can use the Higher Order Component withCreateEvtForwarder. By wrapping a Component in withCreateEvtForwarder, the former will directly receive in its props the evtForwarder that can be used to dispatch and forward as many events as needed.

//Child
const Child = ({ forwardEvt }) => {
    return (
        <div>
            <button
                onClick={() => forwardEvt('message', {msg: 'we are sending you a message'} )}
            >
                send message
            </button>
        </div>
    )
}

export default withCreateEvtForwarder(Child)

// Parent component

const Parent = props => {
    // ...business logic of the compoent
    return <Child onMessage={e => console.log(e.detail.msg)} />
}

Asynchronicity and event chaining

forwardEvt let's you know when the callback has finished running by always returning a Promise that resolves to true after the callback is executed, or to false if there is no callback for the handler.

This opens to the possibility of using .then to perform further actions independently from the Parent Component, or concatenate events.

//Child,  using hooks

import { useState } from 'react'
import { useEvtForwarder } from 'react-event-forward'

const Child = props => {
    const forwardEvt = useEvtForwarder(props)

    return (
        <button
            onClick={() => {
                forwardEvt('message', { msg: 'yooo' })
                    .then(res => res 
                        ? forwardEvt('close')
                        : console.error('a problem ocurred')
                    )
            }}
        >
            Send
        </button>
    )
}

//Parent

export default function Parent({ things }) {
    // business logic of the parent component

  return (
      <Child 
        onClose={closeChild}
        onMessage={e => handleMessage(e.detail.msg)}
    >
  )
}

License

MIT © AyloSrd


This hook is created using create-react-hook.