Install
npm i @bit-about/event
Migrations
v1 -> v2
Events dispatch approach has been changed. There are no longer functions executed using their names in string.
✖️ old one:const dispatch = useEvent() dispatch('onBobPress', 'hello')
✅ new one:const { onBobPress } = useEvent() onBobPress('hello')
Features
- 100% Idiomatic React
- 100% Typescript with event types deduction
- Listen or dispatch events from a hook...
- ...or utilise static access
- No centralized event provider
- Tiny - only 0.6kB
- Just works ™
➡️ Check demo
Usage
import { events } from '@bit-about/event'
const [EventProvider, useEvents] = events({
buttonClicked: (payload: string) => payload,
userLogged: () => {},
modalClosed: () => {},
})
const App = () => (
<EventProvider>
...
</EventProvider>
)
const Button = () => {
const { buttonClicked } = useEvents()
return (
<button onClick={() => buttonClicked('Hello')}>
Call event
</button>
)
}
const Component = () => {
const [message, setMessage] = React.useState('')
useEvents({
buttonClicked: (payload: string) => setMessage(payload)
})
return <p>{message}</p> // "Hello"
}
Static access
The third result element of events()
is object providing access in static manner (without hook).
const [AppEventProvider, useAppEvents, { subscribe, dispatcher }] = events(...)
and then
// 🗣️ Dispatch event
dispatcher.buttonClicked('Hello Allice!')
// 👂 Subscribe and listen on new events
const subscriber = subscribe({
buttonClicked: (payload: string) => console.log(payload)
})
// remember to unsubscribe!
subscriber.unsubscribe()
👉 Re-render
Neither listeners nor events dispatch your components render.
A component will only be rerendered if it's state is explicitly changed (in e.g. React.useState
).
const Component = () => {
const [message, setMessage] = React.useState('')
useEvents({
aliceClicked: () => console.log('I DO NOT rerender this component!'),
bobClicked: () => setMessage('I DO rerender this component!')
})
return <p>{message}</p>
}
Event Middlewares
Events in events()
are payload middlewares. They can transform payload into another.
const [EventProvider, useEvents] = events({
buttonClicked: (payload) => `Hello ${message}!`, // Transforms string payload to another
avatarClicked: () => `Bob!`, // Provides default payload
})
const { buttonClicked, avatarClicked } = useEvents({
buttonClicked: (payload) => console.log(payload), // prints "Hello Alice!",
avatarClicked: (payload) => console.log(payload), // prints "Bob!"
})
buttonClicked('Alice')
avatarClicked()
NOTE:
The library is full type-safe, so Typescript will inform you when you use wrong payload anywhere.
💛 BitAboutState
BitAboutEvent Are you tired of sending logic to a related components?
Move your bussiness logic to hook-based state using @bit-about/state
+ @bit-about/event
.
Now you've got completely type-safe side-effects. Isn't that cool?
import { state } from '@bit-about/state'
import { useEvents } from './auth-events' // Hook generated from events()
import User from '../models/user'
const [UserProvider, useUser] = state(
() => {
const [user, setUser] = React.useState<User | null>(null)
useEvents({
userLogged: (user: User) => setUser(user),
userLoggout: () => setUser(null)
})
return user
}
)
Partners
Credits
- Constate - approach main inspiration
- use-context-selector & FluentUI - fancy rerender avoiding tricks and code main inspiration
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 🙇🏻!