Description
Is your feature request related to a problem? Please describe.
I'm trying to port some code that uses React hooks to Svelte. React has useEffect
, which can be used to run some code when its dependencies change. I think the Svelte equivalent would be reactive statements ($: { doStuff() }
).
When using useEffect
you can return a function, and that function will be called when dependencies change, or when the component using the useEffect
is unmounted. I do not see an equivalent in Svelte.
Here are the relevant docs for useEffect
: https://reactjs.org/docs/hooks-reference.html#cleaning-up-an-effect
Describe the solution you'd like
I think it might be beneficial for Svelte to allow for returning cleanup functions in reactive statements.
In order to allow for returning though I think it would need to be possible to give a function as a reactive statement. Not sure, I'm hoping something like this could be possible though.
// A prop. Some kind of track object that can have listeners.
export let track
// We want to stop all tracks when our stop event listener is called.
// When the track prop is changed to a different track, or when the component is unmounted
// we want to remove the listener.
// This must be a function so we can use a return statement. The function should be called as if it was a statement in the same place.
$: () => {
let onStop = () => track.stopAllTracks()
track.on('stop', onStop)
return () => {
track.off('stop', onStop)
}
}
For reference in React this would look like:
useEffect(() => {
let onStop = () => track.stopAllTracks()
track.on('stop', onStop)
return () => {
track.off('stop', onStop)
}
}, [track])
Describe alternatives you've considered
The closest I could come up with is this:
import { onDestroy } from 'svelte'
export let track
let cleanup
$: {
if (cleanup) {
cleanup()
}
const onStop = () => track.stopAllTracks()
track.on('stop', onStop)
cleanup = () => track.off('stop', onStop)
}
onDestroy(() => {
if (cleanup) {
cleanup()
}
})
This is verbose compared to how useEffect
works. As a React user this seems like a step backwards, feeling more like class
components, lifecycle methods, instance variables, instead of clean like the hooks version.
This could be cleaned up a bit by initializing cleanup
:
import { onDestroy } from 'svelte'
export let track
let cleanup = () => {}
$: {
cleanup()
const onStop = () => track.stopAllTracks()
track.on('stop', onStop)
cleanup = () => track.off('stop', onStop)
}
onDestroy(cleanup)
How important is this feature to you?
It's important to me because I'm trying to convert React code to Svelte code and there doesn't seem to be a clean translation of this common React feature (useEffect
+ cleanup function).
I believe many other users may come from the React ecosystem and encounter this issue.