useEffectEvent
useEffectEvent
is a React Hook that lets you extract non-reactive logic from your Effects into a reusable function called an Effect Event.
const onSomething = useEffectEvent(callback)
Reference
useEffectEvent(callback)
Call useEffectEvent
at the top level of your component to declare an Effect Event. Effect Events are functions you can call inside Effects, such as useEffect
:
import { useEffectEvent, useEffect } 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]);
// ...
}
Parameters
callback
: A function containing the logic for your Effect Event. When you define an Effect Event withuseEffectEvent
, thecallback
always accesses the latest values from props and state when it is invoked. This helps avoid issues with stale closures.
Returns
Returns an Effect Event function. You can call this function inside useEffect
, useLayoutEffect
, or useInsertionEffect
.
Caveats
- Only call inside Effects: Effect Events should only be called within Effects. Define them just before the Effect that uses them. Do not pass them to other components or hooks.
- Not a dependency shortcut: Do not use
useEffectEvent
to avoid specifying dependencies in your Effect’s dependency array. This can hide bugs and make your code harder to understand. Prefer explicit dependencies or use refs to compare previous values if needed. - Use for non-reactive logic: Only use
useEffectEvent
to extract logic that does not depend on changing values.
Usage
Reading the latest props and state
Typically, when you access a reactive value inside an Effect, you must include it in the dependency array. This makes sure your Effect runs again whenever that value changes, which is usually the desired behavior.
But in some cases, you may want to read the most recent props or state inside an Effect without causing the Effect to re-run when those values change.
To read the latest props or state in your Effect, without making those values reactive, include them in an Effect Event.
import { useEffect, useContext, useEffectEvent } from 'react';
function Page({ url }) {
const { items } = useContext(ShoppingCartContext);
const numberOfItems = items.length;
const onNavigate = useEffectEvent((visitedUrl) => {
logVisit(visitedUrl, numberOfItems);
});
useEffect(() => {
onNavigate(url);
}, [url]);
// ...
}
You can pass reactive values like url
as arguments to the Effect Event. This lets you access the latest values without making your Effect re-run for every change.