Skip to content

Commit 601cd92

Browse files
committed
Update useEffectEvent docs for canary
1 parent 170e5b9 commit 601cd92

File tree

6 files changed

+134
-45
lines changed

6 files changed

+134
-45
lines changed

src/content/learn/separating-events-from-effects.md

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -400,13 +400,15 @@ You need a way to separate this non-reactive logic from the reactive Effect arou
400400
401401
### Declaring an Effect Event {/*declaring-an-effect-event*/}
402402
403-
<Wip>
403+
<Canary>
404404
405-
This section describes an **experimental API that has not yet been released** in a stable version of React.
405+
**The `useEffectEvent` API is currently only available in React’s Canary and Experimental channels.**
406406
407-
</Wip>
407+
[Learn more about React’s release channels here.](/community/versioning-policy#all-release-channels)
408408
409-
Use a special Hook called [`useEffectEvent`](/reference/react/experimental_useEffectEvent) to extract this non-reactive logic out of your Effect:
409+
</Canary>
410+
411+
Use a special Hook called [`useEffectEvent`](/reference/react/useEffectEvent) to extract this non-reactive logic out of your Effect:
410412
411413
```js {1,4-6}
412414
import { useEffect, useEffectEvent } from 'react';
@@ -578,11 +580,13 @@ You can think of Effect Events as being very similar to event handlers. The main
578580
579581
### Reading latest props and state with Effect Events {/*reading-latest-props-and-state-with-effect-events*/}
580582
581-
<Wip>
583+
<Canary>
584+
585+
**The `useEffectEvent` API is currently only available in React’s Canary and Experimental channels.**
582586
583-
This section describes an **experimental API that has not yet been released** in a stable version of React.
587+
[Learn more about React’s release channels here.](/community/versioning-policy#all-release-channels)
584588
585-
</Wip>
589+
</Canary>
586590
587591
Effect Events let you fix many patterns where you might be tempted to suppress the dependency linter.
588592
@@ -878,11 +882,13 @@ Read [Removing Effect Dependencies](/learn/removing-effect-dependencies) for oth
878882
879883
### Limitations of Effect Events {/*limitations-of-effect-events*/}
880884
881-
<Wip>
885+
<Canary>
886+
887+
**The `useEffectEvent` API is currently only available in React’s Canary and Experimental channels.**
882888
883-
This section describes an **experimental API that has not yet been released** in a stable version of React.
889+
[Learn more about React’s release channels here.](/community/versioning-policy#all-release-channels)
884890
885-
</Wip>
891+
</Canary>
886892
887893
Effect Events are very limited in how you can use them:
888894

src/content/reference/react/experimental_useEffectEvent.md

Lines changed: 0 additions & 31 deletions
This file was deleted.

src/content/reference/react/useEffect.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1691,11 +1691,13 @@ Now that you define the `createOptions` function inside the Effect, the Effect i
16911691
16921692
### Reading the latest props and state from an Effect {/*reading-the-latest-props-and-state-from-an-effect*/}
16931693
1694-
<Wip>
1694+
<Canary>
16951695
1696-
This section describes an **experimental API that has not yet been released** in a stable version of React.
1696+
**The `useEffectEvent` API is currently only available in React’s Canary and Experimental channels.**
16971697
1698-
</Wip>
1698+
[Learn more about React’s release channels here.](/community/versioning-policy#all-release-channels)
1699+
1700+
</Canary>
16991701
17001702
By default, when you read a reactive value from an Effect, you have to add it as a dependency. This ensures that your Effect "reacts" to every change of that value. For most dependencies, that's the behavior you want.
17011703
@@ -1710,7 +1712,7 @@ function Page({ url, shoppingCart }) {
17101712
}
17111713
```
17121714
1713-
**What if you want to log a new page visit after every `url` change, but *not* if only the `shoppingCart` changes?** You can't exclude `shoppingCart` from dependencies without breaking the [reactivity rules.](#specifying-reactive-dependencies) However, you can express that you *don't want* a piece of code to "react" to changes even though it is called from inside an Effect. [Declare an *Effect Event*](/learn/separating-events-from-effects#declaring-an-effect-event) with the [`useEffectEvent`](/reference/react/experimental_useEffectEvent) Hook, and move the code reading `shoppingCart` inside of it:
1715+
<CanaryBadge /> **What if you want to log a new page visit after every `url` change, but *not* if only the `shoppingCart` changes?** You can't exclude `shoppingCart` from dependencies without breaking the [reactivity rules.](#specifying-reactive-dependencies) However, you can express that you *don't want* a piece of code to "react" to changes even though it is called from inside an Effect. [Declare an *Effect Event*](/learn/separating-events-from-effects#declaring-an-effect-event) with the [`useEffectEvent`](/reference/react/useEffectEvent) Hook, and move the code reading `shoppingCart` inside of it:
17141716
17151717
```js {2-4,7,8}
17161718
function Page({ url, shoppingCart }) {
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
---
2+
title: useEffectEvent
3+
version: canary
4+
---
5+
6+
7+
<Canary>
8+
9+
**The `useEffectEvent` API is currently only available in React’s Canary and Experimental channels.**
10+
11+
[Learn more about React’s release channels here.](/community/versioning-policy#all-release-channels)
12+
13+
</Canary>
14+
15+
<Intro>
16+
17+
`useEffectEvent` is a React Hook that lets you extract non-reactive logic from your Effects into a reusable function called an [Effect Event](/learn/separating-events-from-effects#declaring-an-effect-event).
18+
19+
```js
20+
const onSomething = useEffectEvent(callback)
21+
```
22+
23+
</Intro>
24+
25+
<InlineToc />
26+
27+
## Reference {/*reference*/}
28+
29+
### `useEffectEvent(callback)` {/*useeffectevent*/}
30+
31+
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`:
32+
33+
```js {4-6,11}
34+
import { useEffectEvent, useEffect } from 'react';
35+
36+
function ChatRoom({ roomId, theme }) {
37+
const onConnected = useEffectEvent(() => {
38+
showNotification('Connected!', theme);
39+
});
40+
41+
useEffect(() => {
42+
const connection = createConnection(serverUrl, roomId);
43+
connection.on('connected', () => {
44+
onConnected();
45+
});
46+
connection.connect();
47+
return () => connection.disconnect();
48+
}, [roomId]);
49+
50+
// ...
51+
}
52+
```
53+
54+
[See more examples below.](#usage)
55+
56+
#### Parameters {/*parameters*/}
57+
58+
- `callback`: A function containing the logic for your Effect Event. When you define an Effect Event with `useEffectEvent`, the `callback` always accesses the latest values from props and state when it is invoked. This helps avoid issues with stale closures.
59+
60+
#### Returns {/*returns*/}
61+
62+
Returns an Effect Event function. You can call this function inside `useEffect`, `useLayoutEffect`, or `useInsertionEffect`.
63+
64+
#### Caveats {/*caveats*/}
65+
66+
- **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.
67+
- **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.
68+
- **Use for non-reactive logic:** Only use `useEffectEvent` to extract logic that does not depend on changing values.
69+
70+
___
71+
72+
## Usage {/*usage*/}
73+
74+
### Reading the latest props and state {/*reading-the-latest-props-and-state*/}
75+
76+
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.
77+
78+
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.
79+
80+
To [read the latest props or state](/learn/separating-events-from-effects#reading-latest-props-and-state-with-effect-events) in your Effect, without making those values reactive, include them in an Effect Event.
81+
82+
```js {7-9,12}
83+
import { useEffect, useContext, useEffectEvent } from 'react';
84+
85+
function Page({ url }) {
86+
const { items } = useContext(ShoppingCartContext);
87+
const numberOfItems = items.length;
88+
89+
const onNavigate = useEffectEvent((visitedUrl) => {
90+
logVisit(visitedUrl, numberOfItems);
91+
});
92+
93+
useEffect(() => {
94+
onNavigate(url);
95+
}, [url]);
96+
97+
// ...
98+
}
99+
```
100+
101+
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.
102+

src/sidebarReference.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@
3838
"title": "useEffect",
3939
"path": "/reference/react/useEffect"
4040
},
41+
{
42+
"title": "useEffectEvent",
43+
"path": "/reference/react/useEffectEvent",
44+
"version": "canary"
45+
},
4146
{
4247
"title": "useId",
4348
"path": "/reference/react/useId"

vercel.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,11 @@
248248
"source": "/feed.xml",
249249
"destination": "/rss.xml",
250250
"permanent": true
251+
},
252+
{
253+
"source": "/reference/react/experimental_useEffectEvent",
254+
"destination": "/reference/react/useEffectEvent",
255+
"permanent": true
251256
}
252257
],
253258
"headers": [

0 commit comments

Comments
 (0)