How to Use useEffectEvent Hook in React
Learn how to properly use the experimental useEffectEvent hook in React to handle events inside effects without triggering re-renders. A comprehensive guide with practical examples.

How to Use useEffectEvent Hook in React
React's useEffectEvent is an experimental hook that solves a common problem: reading the latest props or state inside an effect without re-running the effect when those values change.
The Problem It Solves
Consider this common scenario:
function ChatRoom({ roomId, theme }) {
useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.on('connected', () => {
showNotification('Connected!', theme);
});
connection.connect();
return () => connection.disconnect();
}, [roomId, theme]); // ๐ด Reconnects when theme changes!
}
In this example, changing the theme will reconnect to the chat room โ which is not what we want. We only want to reconnect when roomId changes.
The Solution: useEffectEvent
The useEffectEvent hook lets you extract non-reactive logic from your effects:
import { useEffectEvent } from 'react';
function ChatRoom({ roomId, theme }) {
const onConnected = useEffectEvent(() => {
showNotification('Connected!', theme);
});
useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.on('connected', () => {
onConnected();
});
connection.connect();
return () => connection.disconnect();
}, [roomId]); // โ
Only reconnects when roomId changes
}
Key Characteristics
1. Always Reads Latest Values
Effect Events always read the latest values of props and state:
function Timer({ delay, onTick }) {
const tick = useEffectEvent(() => {
onTick(); // Always calls the latest onTick
});
useEffect(() => {
const id = setInterval(tick, delay);
return () => clearInterval(id);
}, [delay]); // โ
No need to include onTick
}
2. Not a Dependency
Effect Events don't need to be listed in the dependency array:
// โ
Correct - no need to add tick to dependencies
useEffect(() => {
const id = setInterval(tick, 1000);
return () => clearInterval(id);
}, []); // tick is stable
3. Synchronous Execution Only
Effect Events should be called from inside effects, not during rendering:
// โ
Correct
useEffect(() => {
myEffectEvent();
}, []);
// ๐ด Wrong - called during render
return <button onClick={myEffectEvent}>Click</button>;
Practical Example: Analytics Tracking
Here's a real-world example of tracking page visits without re-triggering the effect:
function ProductPage({ productId, referrer, userId }) {
const logVisit = useEffectEvent((visitedUrl) => {
// Always reads latest userId and referrer
logAnalytics(visitedUrl, {
referrer,
userId,
timestamp: Date.now(),
});
});
useEffect(() => {
logVisit(`/product/${productId}`);
}, [productId]); // โ
Only logs when productId changes
return <ProductDetails productId={productId} />;
}
When to Use useEffectEvent
| Use Case | useEffectEvent? |
|---|---|
| Read latest props/state in effect | โ Yes |
| Callback passed to effect cleanup | โ Yes |
| Event handlers called during render | โ No |
| Logic that should trigger effect re-run | โ No |
TypeScript Support
The hook is fully typed in React 18+:
import { useEffectEvent } from 'react';
interface NotificationOptions {
message: string;
type: 'success' | 'error' | 'info';
}
function useNotification(defaultType: NotificationOptions['type']) {
const show = useEffectEvent((message: string) => {
showToast({ message, type: defaultType });
});
return { show };
}
Important Notes
โ ๏ธ Experimental Feature:
useEffectEventis still experimental in React 18.x. The API may change before the final release.
To use it today, you may need to import from a canary release:
npm install react@canary react-dom@canary
Comparison with useCallback
| Feature | useCallback | useEffectEvent |
|---|---|---|
| Returns stable reference | โ With deps | โ Always |
| Reads latest values | Only with deps | โ Always |
| Can be used in JSX | โ Yes | โ No |
| Is a dependency | โ Yes | โ No |
Conclusion
The useEffectEvent hook is a powerful addition to React's hooks arsenal. It elegantly solves the problem of reading latest values inside effects without causing unnecessary re-executions.
Key takeaways:
- Use
useEffectEventfor non-reactive logic inside effects - Effect Events always read the latest props and state
- They don't need to be listed as dependencies
- Only call them from inside effects, not during render
Want to learn more about React hooks and best practices? Contact us for custom training or consulting.
Ananas Studio
Software Development Team
Building modern software solutions at Ananas Studio. We specialize in React, Next.js, and scalable architectures.

