New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add $effect.root rune #9638
Conversation
🦋 Changeset detectedLatest commit: f08a4cc The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
757dc29
to
ad64744
Compare
feat: add $effect.root rune update doc update doc fix validation
2150235
to
d7367dc
Compare
Could class Counter {
count = $state(0);
constructor(count) {
this.count = count;
this.cleanupCountLogger = $effect(() => { console.log(this.count); });
}
dispose() {
this.cleanupCountLogger();
}
} Just an idea, but I understand if that's not explicit enough. In any case, I'd not expect that an $effect is auto-cleaned up when used within a class, as the class instance's lifecycle is likely completely unrelated to the lifecycle of the components. So to me the restriction that $effect may only be called within the boundary of component initialization seems a bit arbitrary. Better be explicit about cleanup when $effect is used in code outside of components? |
@michael I don't think we want to do that, as it'll be difficult to know if people are using effects properly and are disposing of them. This API is intended to be an advanced feature, so if people use it, they should expect to go out of the way to clean up their memory properly too. In the naive case, I just don't see how we can guarantee that if we make everything return a cleanup expression. |
sites/svelte-5-preview/src/routes/docs/content/01-api/02-runes.md
Outdated
Show resolved
Hide resolved
I've updated the PR to remove the 2nd argument from |
Yeah would definitely need more self-responsibility. And it's a good thing $effect does auto-cleanup inside components. The solution with $effect.root is fine I guess, just leaves a bit of ambiguity, like users will likely use $effect outside of components when they're not really designed for that primarily. And then occasionally run into the problem I had (ERR_SVELTE_ORPHAN_EFFECT), and switch to $effect.root. As for myself I will either go for $effect.root (once it's released) or only use $effect from the component so it has a clear lifecycle. Just one question: When using $derived as class fields, I don't have to worry about this right? |
@michael Derived is fine. We might also add an API to make it easier to understand if you're inside a parent component effect. |
Seems like this PR closes #9269, which is great! One question though, I suppose the reason why cleanup isn't being passed to the root fn is because it can be potentially confusing? I'd think makes // Let's have a persistent counter
const counter = $effect.root((cleanup) => {
let count = $state(0);
$effect(() => {
// persist the count
});
return {
get count () { return count; },
set count (next) { count = next; },
// ... additional methods ...
cleanup,
};
});
counter.count = 8;
// We don't need it anymore, goodbye!
counter.cleanup(); |
The
$effect.root
rune is an advanced feature that creates a non-tracked scope that doesn't auto-cleanup. This is useful for nested effects that you want to manually control. This rune also allows for creation of effects outside of the component initialisation phase.