This is an experimental API, but helps with one of the big problems with [[20220815044638-useeffect]], separating reactive and non-reactive logic.
Props, state, and variables declared inside your component’s body are called reactive values. Reactive values can change due to a re-render. Logic inside effects is reactive. Logic inside event handlers is not reactive. It does not run automatically. Event handlers can read reactive values without “reacting” to their changes.
function ChatRoom({ roomId, theme }) {
useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.on('connected', () => {
showNotification('Connected!', theme);
});
connection.connect();
// ...
As both roomId
and theme
are reactive, both should be in the deps array.
function ChatRoom({ roomId, theme }) { useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.on('connected', () => { showNotification('Connected!', theme); }); connection.connect(); return () => { connection.disconnect() }; }, [roomId, theme]); // ✅ All dependencies declared // ...
However, You don't want this to execute based on the theme
changing, only if the roomId
does. The above code has an issue - if the theme changes, it will re-connect to the room.
You need a way to separate this non-reactive logic from the reactive Effect around it.
React has some suggestions on how to solve this problem (https://react.dev/learn/removing-effect-dependencies#removing-unnecessary-dependencies). Which are loosely:
This is where useEffectEvent
comes in. It's currently still experimental, but in the above example, it would allow you to separate the non-reactive logic out:
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]); // ✅ All dependencies declared // ...
React docs mentions the following:
After
useEffectEvent
becomes a stable part of React, we recommend never suppressing the linter.