BitAboutEvent
? 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
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