DEV Community

Cover image for Simplifying React with EventEmitter: Reduce Prop Drilling & Unnecessary Re-renders
RakibRahman
RakibRahman

Posted on

3 1 1 1

Simplifying React with EventEmitter: Reduce Prop Drilling & Unnecessary Re-renders

Intro

In React applications, state management tools like Redux, Zustand, or React Context help manage shared data across components. However, when it comes to event-driven communication, EventEmitter can be a lightweight and efficient alternative. It enables components to interact without deep prop drilling or unnecessary re-renders. In this blog, we'll explore how EventEmitter works, how to implement it in React, and when it’s the right tool for the job.

What's an Event Emitter?

In browsers, we handle user interactions using events. An event can be triggered by a user's action, such as a mouse click or a keyboard key press. For example, when we copy and paste text or media files into our app, it’s handled by the ClipboardEvent to achieve the desired outcome. Different frameworks and libraries provide various implementations of this concept. In Node.js, the EventEmitter class offers a simple and flexible way to handle events. Simply put, it emits (or triggers) an event that anyone can listen to and perform tasks based on the emitted data.

Basic Example of EventEmitter in JavaScript

Here’s a basic implementation of EventEmitter in JavaScript using Node.js' built-in EventEmitter class.

event emitter node js

  • The emit method is used to trigger an event. In this example, it triggers the login event and passes the phone number ('01829546') as data.
  • The on method is used to listen for an event and execute a callback function when the event is triggered. Here, it invokes the sendOTP function with the provided phone number.

Implementing EventEmitter in React

React doesn’t have a built-in EventEmitter, so we’ll use the eventemitter3 package from npm. This approach allows us to manage app-wide events without tightly coupling components.

Step 1: Setting Up EventEmitter

Let’s create a file (eventEmitter.ts) to define and export a single instance of EventEmitter. This ensures that the same instance is shared across the entire application.

event emitter 3 react

Step 2: Emitting an Event from Any Component

The LoginButton component emits an event named login with a phone number as data.

event emit

Step 3: Subscribing to the Event from Any Component

event on

  • The OTPHandler component listens for the login event and performs an action.
  • Components can listen for events even if they are not directly related to the emitter component. This eliminates the need for deep prop drilling, as the data is available app-wide.

Code Example Repo

Benefits of Using EventEmitter

  • Decoupling Logic: The LoginButton and OTPHandler components are completely independent. They communicate via the shared AppEmitter instance.
  • Preventing Deep Prop Passing: You don’t need to pass props through deeply nested components, as the event data is globally accessible.
  • Avoiding Re-renders: Since events are handled outside of React's state management, unrelated components won’t re-render unnecessarily.
  • App-Wide Notifications: EventEmitter is useful for broadcasting notifications, logging, or analytics across the app.

Drawbacks of EventEmitter

  • Hard to Debug: Events are decoupled, making it difficult to trace where an event was emitted or which listeners handle it, especially as the application grows.
  • Memory Leaks: If listeners are not cleaned up (e.g., using .off()), they can persist after components are unmounted, leading to memory leaks and unexpected behaviour.
  • No Built-in Error Handling: Errors in listeners can crash the application since EventEmitter does not provide robust error-handling mechanisms.
  • Not for Complex State Management: EventEmitter is unsuitable for managing complex state or workflows. It’s designed for simple event-driven communication, not for maintaining synchronized application state

EventEmitter, React Context, Redux/Zustand: Which Tool Fits Your Use Case?

  • EventEmitter: Best for event-driven workflows (e.g., logging, analytics). Avoids re-renders but requires manual cleanup and lacks built-in error handling.
  • React Context: Ideal for shared UI state (e.g., themes, auth). Easy to use but triggers frequent re-renders, making it less efficient for high-frequency updates.
  • Redux/Zustand: Perfect for complex global state (e.g., complex business logic) in large apps. Offers scalability and middleware support.
Feature EventEmitter React Context Redux/Zustand
Decoupling High Low Medium
Re-render Optimization Yes (operates outside React lifecycle) No (triggers re-renders for listeners) Depends on setup
Use Case Event-driven workflows (e.g., logging, analytics, WebSocket events) Shared UI state (e.g., themes, user auth) Complex app state (e.g., large-scale apps)
Memory Management Requires manual cleanup (.off()) Automatically managed by React Automatically managed by library
Error Handling Manual (no built-in mechanisms) Manual Built-in middleware support
Scalability Good for small-to-medium apps Good for medium apps Excellent for large-scale apps
Performance Overhead Minimal Moderate (re-renders can be costly) Moderate to High (depends on usage)

Conclusion

EventEmitter is a powerful tool for event-driven workflows, allowing React components to communicate without deep prop drilling or excessive state management. While it helps optimize performance by preventing unnecessary re-renders, it comes with trade-offs like manual cleanup and lack of built-in error handling. When used correctly, EventEmitter can be a lightweight and efficient alternative for handling app-wide notifications, logging, and one-time interactions. However, for managing complex application states, React Context or state management libraries like Redux and Zustand remain more suitable options.

That wraps up our deep dive into EventEmitter!. Thank you for reading, and don't forget to connect on LinkedIn or X to get more content.

If you have any questions or feedback, please leave a comment.

SurveyJS custom survey software

JavaScript UI Libraries for Surveys and Forms

SurveyJS lets you build a JSON-based form management system that integrates with any backend, giving you full control over your data and no user limits. Includes support for custom question types, skip logic, integrated CCS editor, PDF export, real-time analytics & more.

Learn more

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs