BitAboutEvent

Bundle size ? Tiny and powerful hook-based event system for React. 100% Idiomatic React.

Install

npm install --save @bit-about/event

Features

  • 100% Idiomatic React
  • 100% Typescript with event types deduction
  • Efficient and hook-based
  • No centralized event provider
  • Tiny – only 100KB
  • Just works

Usage

1️⃣ Define your events set and their payloads

import { events } from '@bit-about/event'

const [EventProvider, useEvent] = events({
  buttonClicked: (payload: string) => payload,
  userLogged: () => {},
  modalClosed: () => {},
})

2️⃣ Wrap the tree with the EventProvider

const App = () => (
  <EventProvider>
    {/* ... */}
  </EventProvider>
)

Listen and dispatch your defined event in type-safe manner

const Button = () => {
  const dispatchEvent = useEvent()
  
  // ?️ Dispatch events
  const onButtonClick = () => dispatchEvent('buttonClicked', "Hello")
  
  return <button onClick={onButtonClick}>Call event</button>
}

const Component = () => {
  const [message, setMessage] = React.useState("")

  // ? Listen on events
  useEvent({
    buttonClicked: (payload: string) => setMessage(payload)
  })
  
  return <p>{message}</p>
}

You don’t need to think too much – it’s easy, look:

  • define events with payloads using events()
  • wrap the components tree with the generated EventProvider
  • listen on events with useEvent hook
  • dispatch events with useEvent hook

Event Middlewares

Events in events() are actually payload middlewares.

const [EventProvider, useEvent] = events({
  buttonClicked: (payload: string) => `Hello ${message}!`,
})

const dispatchEvent = useEvent({
  buttonClicked: (payload: string) => console.log(payload) // "Hello Alice!"
})

dispatchEvent('buttonClicked', "Alice")

NOTE: The library is completely type safe so Typescript will inform you when you use wrong payload anywhere

Default payload

When you don’t need the payload and want some default object, you can omit middleware parameters.

const [EventProvider, useEvent] = events({
  buttonClicked: () => `Bob!`,
})

const dispatchEvent = useEvent({
  buttonClicked: (payload: string) => console.log(payload) // "Bob!"
})

dispatchEvent('buttonClicked')

Middleware helpers

Are you an aesthete? Try: withPayload<PayloadType>(), withDefault(defaultPayload) and withNothing.

const [EventProvider, useEvent] = events({
  userLogged: withPayload<{ id: number }>(),
  homeVisited: withNothing,
  buttonClicked: withDefault({ type: 'userButton' })
})

NOTE: withPayload does the call with (). If you forget about it, your payload will be the function ?

? Rerendering

Neither listeners nor event dispatching rerender the component. The component will only be rerendered if its state is explicitly changed (in e.g. React.useState).

const Component = () => {
  const [message, setMessage] = React.useState("")

  useEvent({
    aliceClicked: () => console.log("I DON'T rerender this component!"),
    bobClicked: () => setMessage("I DO rerender this component!")
  })
  
  // ...
}

BitAboutEvent ? BitAboutState

Are you tired of sending logic to the related components? Move your bussiness logic to the hook-based state using @bit-about/state + @bit-about/event.

Now you’ve got completely type-safe side-effects, isn’t cool?

import { state } from '@bit-about/state'
import { useEvent } from './user-events'
import User from '../models/user'

const [AuthProvider, useAuth] = state(
  () => {
    const [user, setUser] = React.useState<User | null>(null)
    
    useEvent({
      userLogged: (user: User) => setUser(user),
      userLoggout: () => setUser(null)
    })
    
    return { user }
  }
)

Partners

wayfdigital.com

Credits

License

MIT © Maciej Olejnik ??

Support me

If you use my library and you like it… it would be nice if you put the name BitAboutEvent in the work experience section of your resume. Thanks ??!


?? Slava Ukraini

GitHub

View Github