Comments (8)
Do you have a specific use case in mind?
from svelte.
I haven't encountered one. I came up with the idea while writing the internals of Svelte-5-like nano reactivity system that I plan to use for educational purposes. I just thought it might be useful for someone at some point (hello Googler from 3 years down the line 👋).
I also had another idea which would be to pass the return value of the cleanup as an $effect
argument. It might just keep things a little bit more "compartmentalised", tied into the lifecycle of the $effect
itself rather than needing to work with external state. I won't cry if it's not implemented, but it might make things just a tad bit neater. Who knows it might be useful for something like debouncing api requests or something.
$effect((count) => {
if (count === undefined) count = 1
console.log("The " + statefulVar + " has changed " + count + " times")
return () => {
console.log("Cleaning up and incrementing count")
count + 1
}
})
from svelte.
Here's a use case actually, say I need to debounce and update some state. I can do something like this. Might be nice to have it neat and all tucked into an $effect
rather than have state spilling out all over the place. Neat and tidy.
$effect((timeoutID) => {
clearTimeout(timeoutID)
const someApiCall = runOnce(() => /* fetch(statefulStuff) */)
timeoutID = setTimeout(timeoutID, 1000)
return (destroyed) {
if (destroyed) {
clearTimeout(timeoutID)
someApiCall()
} else {
return timeoutID
}
}
})
from svelte.
There has been at least a little bit of internal conversation about something like this. I had floated it as an idea for a way to let $effect
functions know whether they should completely clean up after themselves (when they're destroyed) or whether they should just make some adjustments to what happens when various listeners/etc. are run. I ended up deciding that having nested/sibling $effect
blocks was probably the way to go here - one of which wouldn't be torn down until the whole component was being destroyed, and the other of which would be torn down when there were other kinds of changes - without requiring any additional functionality. I haven't come up with a concrete case where knowing whether an $effect
was being destroyed or being re-created is actually helpful.
from svelte.
What about moving the destroying logic to the onDestroy
and hoisting all the necessary variables to the script level so that they are available in the onDestroy
?
from svelte.
I don't understand why the callback is called before each run of $effect
, rather than just when the component is destroyed. Not saying it's wrong to do so -- I just can't think of a pattern where it'd be useful. The $effect
body already runs each time the state it references changes, so presumably all the "update" logic can go there.
let open = $state(false);
let focusTrap: FocusTrap|undefined = undefined;
$effect(() => {
if (!focusTrap) {
focusTrap = createFocusTrap(/*some init*/);
}
if (open) {
focusTrap.activate();
} else {
focusTrap.deactivate();
}
return () => {
// seems like this would be redundant on update, given the code above
focusTrap.deactivate()
}
})
from svelte.
I don't understand why the callback is called before each run of $effect, rather than just when the component is destroyed.
It requires you to have those resources on the global scope, though. Otherwise you cannot refer to the previous version of the resource in order to clean it up. Cleaning it up in the cleanup function which is ran each time the effect refires can just keep the variable in the effect function, as closure
especially with things like event listeners (if there is ever a use case for that), the above code wouldn't precisely work, and you get something like
let listener: ((evt: Event) => void)|undefined = undefined
$effect(() => {
if(listener) {
//Hoping that el is not a state which changed, otherwise this is even uglier with a previousEl which needs to be updated by the effect in order to clean the listener up
el.removeEventListener('event', listener)
}
// listener depends on the state this effect listens to
listener = evt => { /*...*/ }
el.addEventListener(listener)
return () => el.removeEventListener(listener) // Needed anyway, when component is destroyed. If it wouldn't run each time, the mess at the top of the function is needed
})
which is less clean than just keeping the previous element and listener within the cleanup closure which needs to exist anyway
(Granted, I know this is not the best example, an action is much better for this, but there are probably resources which work the same as event listeners in this regard)
from svelte.
@MotionlessTrain Thanks, I get it. If in your example el
was a property of the component (not a bound html element in the component's own markup) we'd have remove the listener each time $effect ran.
from svelte.
Related Issues (20)
- $derived rune on Set object does not re-render on update HOT 2
- Svelte 5: Cannot specify `this`' type in TypeScript HOT 3
- Accessibility warning: href shouldn't be required when aria-disabled="true"
- Svelte 5: confusing behaviour with syntactically invalid attribute expressions HOT 2
- Add rune to more easily combine reactive values and state objects HOT 5
- Passing a Writable as prop to a component doesn't allow "$" access HOT 2
- Svelte 5: dynamic class name not supported on SVG
- Svelte 5: Monkeypatching introduced in #11610 has broken array_prototype.lastIndexOf()
- Svelte version @5.0.0-next.140 breaks Svelte-dnd-action HOT 9
- DOM does not update when using array of objects in $state.frozen() HOT 4
- Svelte 5: onanimationend event doesn't get called under these specific circumstances. HOT 1
- Svelte v5 (maybe v4 too?) incorrectly removes CSS selectors alleging they are unused HOT 9
- Disable paste rather then copy in the tutorial. HOT 2
- Immer JS doesn't work with svelte runes HOT 5
- 5.0.0-next.138 breaks nested global CSS-attribute selectors
- 5.0.0-next.140 blocks pre-render capabilities of $effect.pre() HOT 6
- Svelte action update doesn't trigger on classes HOT 4
- Svelte 5: CSS custom property wrapper is implemented incorrectly HOT 5
- svelte 5: gotpointercapture and lostpointercapture not paresed correctly
- Anchor Tags Triggering Old URLs in Android Chrome HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from svelte.