event
event copied to clipboard
π« Tiny and powerful hook-based event system for React
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
1οΈβ£ Define your events by defining their payload middlewares
import { events } from '@bit-about/event'
const [EventProvider, useEvents] = events({
buttonClicked: (payload: string) => payload,
userLogged: () => {},
modalClosed: () => {},
})
2οΈβ£ Wrap your components in EventProvider
const App = () => (
<EventProvider>
...
</EventProvider>
)
π£οΈ Dispatch your events in one place...
const Button = () => {
const { buttonClicked } = useEvents()
return (
<button onClick={() => buttonClicked('Hello')}>
Call event
</button>
)
}
π ...and listen for them in another
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.
BitAboutEvent π BitAboutState
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 ππ»!
πΊπ¦ Slava Ukraini
