When building React applications, managing state across components can become challenging. While solutions like Context API, Redux, or Zustand are popular choices, there's a simpler native browser feature we can leverage: Custom Events.
What are Custom Events?
Custom Events are part of the native Browser Event API that allows you to create and dispatch custom events throughout your application. They provide a lightweight, decoupled way to communicate between components without prop drilling or complex state management libraries.
Why Use Custom Events?
- Native Browser API - No additional dependencies are required.
- Decoupled Communication - Components can communicate without direct relationships.
- Simple Implementation - Easy to set up and maintain.
- Performance - Lightweight alternative to global state management.
- Type Safety - Can be fully typed with TypeScript.
Implementation Example
Let's look at a practical example of implementing a modal system using Custom Events.
1. Define Your Custom Events
First, create an interface to define your custom events:
export interface CustomEvents {
'modal-event': {
action: 'open' | 'close'
}
}
2. Create a Trigger Function
Create a helper function to dispatch custom events:
export const triggerCustomEvent = <EventName extends keyof CustomEvents>(
eventName: EventName,
data: CustomEvents[EventName]
) => {
const event = new CustomEvent(eventName, { detail: data })
document.dispatchEvent(event)
}
3. Create a Custom Hook
Create a hook to listen for custom events:
export function useEventListener<T extends keyof CustomEvents>(
eventName: T,
handler: (detail: CustomEvents[T]) => void
) {
useEffect(() => {
const eventHandler = (event: CustomEvent<CustomEvents[T]>) => {
handler(event.detail)
}
document.addEventListener(eventName, eventHandler as EventListener)
return () => {
document.removeEventListener(eventName, eventHandler as EventListener)
}
}, [eventName, handler])
}
Usage Example
Here's how to implement a modal system using Custom Events:
Triggering the Modal:
const handleOpenModal = () => {
triggerCustomEvent('modal-event', { action: 'open' })
}
Modal Component:
export const FeedbackModal: React.FC = () => {
const [isOpen, setIsOpen] = useState(false)
useEventListener('modal-event', ({ action }) => {
switch (action) {
case 'open':
setIsOpen(true)
break
case 'close':
setIsOpen(false)
break
}
})
Real-World Benefits
Let's examine a practical scenario where Custom Events shine. In our example application, we have three separate components (Header, Content, and Footer) that all need to trigger the same modal:
export default function Home() {
return (
<div>
<Header />
<Content />
<Footer />
<FeedbackModal />
</div>
)
}
Instead of:
- Lifting state up to a common parent
- Using Context API
- Implementing a state management library
- Prop drilling
We simply:
- Define our custom event
- Trigger it from anywhere
- Listen for it where needed
Best Practices
- Type Safety: Always define your custom event interfaces
- Event Naming: Use clear, descriptive event names
- Cleanup: Always remove event listeners in useEffect cleanup
- Payload Structure: Keep event payloads simple and well-defined
When to Use Custom Events
Custom Events are particularly useful when:
- Components need to communicate across different parts of the application
- You want to avoid prop drilling
- You need a lightweight alternative to global state management
- Components need to react to actions without direct relationships
When Not to Use Custom Events
Consider alternatives when:
- You need persistent state
- You require state synchronization across multiple tabs
- You need to handle complex state logic
- You need to track state history
Conclusion
Custom Events provides a simple, powerful way to handle component communication in React applications. While they might not replace full-state management libraries for complex applications, they offer a lightweight solution for many common scenarios.
The beauty of this approach lies in its simplicity and use of native browser features. It's a reminder that sometimes the best solutions are the ones built into the platform itself.
This implementation demonstrates how we can leverage browser APIs to create clean, maintainable code without unnecessary dependencies. The full example code is available in the provided repository, showing how Custom Events can elegantly solve cross-component communication challenges.
Repo: https://github.com/AdrianKnapp/custom-events
Try it out: https://custom-events-iota.vercel.app/
Top comments (9)
I used this approach years ago on an old class based React app, here's a few things I learned:
Well said, @ansa70! All these points are very important. I think I covered each one in my implementation. Did you notice if I forgot something?
Just an FYI, the event paradigm in react becomes highly problematic. It's just as bad as combining angular and react in a real world application. They know nothing of each other and you end up with the worst of both worlds. Architecture is the solution, but this solution becomes an uneconomical problem, as it usually does when you bypass the original intent and integrations your main framework vendor intended you to use.
That being said, it is a good implementation since it's isolated, I usually see all this inside the main 800 line react function, lol. Really though, they should be converted to state hooks and lifted if appropriate. Remember react has a virtual dom, not the browser dom... your editing the browser dom there I think without telling react... so the react state becomes invalid. Worst, human devs end up having no idea what's happening. I love events... but if you use em, definitely you shouldn't be using react... they work very well with pure js, very bad with react, thee hath been warned... one need not two systems of managing events.
New devs should pay attention to this ^ comment
Maybe you'd want to take a look at useSyncExternalStore
Nice, thanks for the recommendation, I'm gonna take a look!
Interesting, even though I knew browser custom events, I never considered the potential to use them to handle state in React apps, it's the kind of knowledge that is worth having in my pocket
Absolutely, Jean! It's very useful and you can customize whatever you want. Glad this helped you, thanks for reading!
Great breakdown of using Custom Events in React! 🚀 This is a smart alternative to prop drilling and global state management. The simplicity and native API usage make it super efficient. Thanks for sharing!