@ -678,6 +678,52 @@ On the other hand, the Effect itself remains reactive. Code inside the Effect us
As a result, you will call `logVisit` for every change to the `url`, and always read the latest `numberOfItems`. However, if `numberOfItems` changes on its own, this will not cause any of the code to re-run.
<Note>
You might be wondering if you could call `onVisit()` with no arguments, and read the `url` inside it:
```js {2,6}
const onVisit = useEvent(() => {
logVisit(url, numberOfItems);
});
useEffect(() => {
onVisit();
}, [url]);
```
Although this would work too, it is better to pass the `url` that the user visited to the Event function explicitly. **By making `url` an argument to your Event function, you are saying that visiting a page with a different `url` constitutes a separate event from the user's perspective.** It's a part of your "event":
```js {1-2,6}
const onVisit = useEvent(visitedUrl => {
logVisit(visitedUrl, numberOfItems);
});
useEffect(() => {
onVisit(url);
}, [url]);
```
This makes it less likely that someone will remove `url` as a dependency of your Effect, resulting in all the different page visits being counted as a single visit. Your Event function explicitly "asks" for the `visitedUrl`. This communicates to the reader that, from the user's perspective, `onVisit` calls with different `visitedUrl` values are distinct "events". The user has *visited a page with a certain URL.* Page visits should be reactive with respect to `url`, so you pass the `url` from the reactive code in your Effect.
This becomes especially important if there is some asynchronous logic inside the Effect:
```js {6,8}
const onVisit = useEvent(visitedUrl => {
logVisit(visitedUrl, numberOfItems);
});
useEffect(() => {
setTimeout(() => {
onVisit(url);
}, 5000); // Delay logging visits
}, [url]);
```
In this example, `url` inside `onVisit` corresponds to the *latest*`url` (which could have already changed), but `visitedUrl` corresponds to the `url` that originally caused this Effect (and this `onVisit` call) to run.
</Note>
<DeepDivetitle="Is it okay to suppress the dependency linter instead?">
In the existing codebases, you may sometimes see the lint rule suppressed like this:
@ -1395,7 +1441,7 @@ When you join a chat room, this component shows a notification. However, it does
This almost works, but there is a bug. Try changing the dropdown from "general" to "travel" and then to "music" very quickly. If you do it fast enough, you will see two notifications (as expected!) but they will *both* say "Welcome to music".
Fix it so that when you switch from "general" to "travel" and then to "music" very quickly, you see two notifications, the first one being "Welcome to travel" and the second one being "Welcome to music".
Fix it so that when you switch from "general" to "travel" and then to "music" very quickly, you see two notifications, the first one being "Welcome to travel" and the second one being "Welcome to music". (For an additional challenge, assuming you've *already* made the notifications show the correct rooms, change the code so that only the latter notification is displayed.)
The Effect that had `roomId` set to `"travel"` (so it connected to the `"travel"` room) will show the notification for `"travel"`. The Effect that had `roomId` set to `"music"` (so it connected to the `"music"` room) will show the notification for `"music"`. In other words, `connectedRoomId` comes from your Effect (which is reactive), while `theme` always uses the latest value.
To solve the additional challenge, save the notification timeout ID and clear it in the cleanup function of your Effect:
<Sandpack>
```json package.json hidden
{
"dependencies": {
"react": "latest",
"react-dom": "latest",
"react-scripts": "latest",
"toastify-js": "1.12.0"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
}
}
```
```js
import { useState, useEffect } from 'react';
import { useEvent } from './useEvent.js';
import { createConnection, sendMessage } from './chat.js';
import { showNotification } from './notifications.js';
const serverUrl = 'https://localhost:1234';
function ChatRoom({ roomId, theme }) {
const onConnected = useEvent(connectedRoomId => {
showNotification('Welcome to ' + connectedRoomId, theme);