Skip to content

Commit e67050a

Browse files
committed
tweak useEffectEvent
1 parent e51c6e2 commit e67050a

File tree

1 file changed

+9
-7
lines changed

1 file changed

+9
-7
lines changed

src/content/blog/2025/10/01/react-19-2.md

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ See the [Component track docs](/reference/dev-tools/react-performance-tracks#com
9191

9292
### `useEffectEvent` {/*use-effect-event*/}
9393

94-
When using Effects you may want to read the most recent props or state inside an Effect without re-running the Effect when those values change. For example, in the following code the `theme` prop is used inside an Effect, but we don’t want the Effect to re-run when `theme` changes:
94+
One common pattern with useEffect is to notify the app code about some kind of "events" in an external system. For example, a chat room may get connected, and you might want to display a notification when that happens:
9595

9696
```js {5,11}
9797
function ChatRoom({ roomId, theme }) {
@@ -108,29 +108,31 @@ function ChatRoom({ roomId, theme }) {
108108
// ...
109109
```
110110
111-
To solve this, most users just disable the lint rule and exclude the dependency. But that can lead to bugs since the linter can no longer help you keep the dependencies up to date if you need to update the Effect later.
111+
The problem with the code above is that any values used inside such an "event" will cause the surrounding Effect to re-run when they change. For example, changing the theme will cause the chat room to reconnect. This behavior makes sense for values that are related to the Effect logic itself, like roomId, but it doesn't make sense for theme.
112112
113-
React 19.2 introduces `useEffectEvent`, which lets you declare "Effect Events" that can be called inside Effects. Effect Events always access the latest values from props and state when they are invoked, so you can read the latest values without re-running the Effect:
113+
To solve this, most users just disable the lint rule and exclude the dependency. But that can lead to bugs since the linter can no longer help you keep the dependencies up to date if you need to update the Effect later.
114114
115-
With `useEffectEvent`, we can define the `onConnected` callback as an "Effect Event". Now, it doesn't re-run when the values change, but it can still “see” the latest values of your props and state:
115+
With `useEffectEvent`, you can split the "event" part of this logic out of the Effect that emits it:
116116
117117
```js {2,3,4,9}
118-
function ChatRoom({ roomId, theme, threadId }) {
118+
function ChatRoom({ roomId, theme }) {
119119
const onConnected = useEffectEvent(() => {
120120
showNotification('Connected!', theme);
121121
});
122122

123123
useEffect(() => {
124-
const connection = createConnection(serverUrl, roomId, threadId);
124+
const connection = createConnection(serverUrl, roomId);
125125
connection.on('connected', () => {
126126
onConnected();
127127
});
128128
connection.connect();
129129
return () => connection.disconnect();
130-
}, [roomId, threadId]); // ✅ All dependencies declared
130+
}, [roomId]); // ✅ All dependencies declared
131131
// ...
132132
```
133133
134+
Similar to DOM events, Effect Events always "see" the latest props and state. They should not be declared in the dependency array. They can only be declared in the same component or Hook, which is verified by the linter.
135+
134136
<Note>
135137
136138
#### When to use `useEffectEvent` {/*when-to-use-useeffectevent*/}

0 commit comments

Comments
 (0)