-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
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
WIP: Add $effect.sync
rune
#12959
WIP: Add $effect.sync
rune
#12959
Conversation
|
@trueadm based on our conversation I thought it'd be easier to explore with a PR. I saw that If this is not going to work, I'd love to understand why. If it could work and there's interest, I will continue with compiler updates, tests, docs, etc. |
Inspect effects don't mutate anything, so they're harmless to the reactive graph. |
I see how the code I had could cause issues if the sync effects scheduled other sync effects. I pushed something I think should fix that. Here are the main issues you've raised, as I've understood them: OverfiringSync effects could easily overfire. Simple example: let a = $state(0);
let b = $state(1);
$effect.sync(() => {
console.log('Sum is', a + b);
});
function increment() {
// will trigger the effect twice in a row, one for each change
a += 1;
b += 1;
} More subtle example: let a = $state(0);
$effect.sync(() => {
if (a % 2 !== 0) {
a -= 1;
}
});
$effect.sync(() => {
console.log(a);
});
// Should cause the first effect to fire twice.
//
// Should also cause the second effect to fire twice.
// If I've traced it correctly, both runs would log `2`
// and the `3` would never be logged. If the effects
// were ordered differently, it would probably log `3`
// and then `2`.
a += 3; I personally don't think that the overfiring is a big deal. It's an issue if you're using sync effects generally but I don't think it's a big problem in the situations where you would actually need to reach for them. Could be wrong. Out-of-order triggeringYou mentioned that there was a specific order the effects are supposed to trigger in. I don't understand it all, but I'm comfortable saying that "sync effects are not guaranteed to run in a specific order. If you're depending on multiple sync effects running in a particular order, please reconsider your use case." In reality, I expect that the sync effects would trigger in the order that they are registered, depth-first (i.e. any sync effects triggered by the first effect would run before the other sync effects). Possible breakdown of the reactive graph entirely?I haven't been able to come up with how this could be, so if you have an example please share. Obviously sync effects have pitfalls, and there's a reason they're not the default. But I think it can be exposed as an option, with the appropriate caveats. |
|
There's no question that sync effects have more footguns and less guarantees. But I believe they should be an available tool for the occasional scenario where they're useful. @trueadm do you disagree? EDIT: nice example by the way, that's helpful to understand some of the issues |
@mimbrown We used to have an unofficial sync effect but it was far too buggy and caused so many issues because of the async effects having a different timing and thus co-ordination failed. There are compounding issues, but realistically I don't think we re-introduce them again – not unless we want to remove transitions/animations from Svelte – because sync effects cannot exist when you have transitions working on a different timing schedule. As you can see |
I get that, if you're ever trying to "coordinate" sync and async effects, you're gonna have a bad time. The use cases I have in mind don't want to coordinate with any async effects. The reason this came up (as you know) was because of the example Rich posted about using an effect to emulate the just-removed let a = $state(0);
let b = $state(a);
$effect(() => {
b = a;
});
a = 1;
console.log(b); // expect 1, but actually 0 This would be a valid use case for You could even pull a react and call it |
I don’t know if it is worth going down this rabbit hole of trying to add a sync effect when it seems that it’s more likely to solve the original issue with some form of a writable derived |
Exactly. Deriveds are the correct solution for this problem, we just need a mutable version or some permutation of it in the future that deals with this use case. |
There's probably an alternative solution to this problem, but I doubt this is the only time a sync effect would be useful. Here's what the Vue docs say:
So pretty much exactly what I'm proposing: "You might need this, we support it, use with caution." |
We have |
This comment was marked as duplicate.
This comment was marked as duplicate.
@trueadm isn't |
@mimbrown Yes, you need to flush everything. If you have a parent For these reasons, we're not going to introduce sync effects in to Svelte 5. I hope all the details in nuance here make sense as to why this isn't feasible too. :) |
WORK IN PROGRESS
This PR adds a new
$effect.sync
rune for synchronous effects.Based on this off-topic conversation thread that I caused.
Changes
$effect.sync
as a supported rune to the compiler.Before submitting the PR, please make sure you do the following
feat:
,fix:
,chore:
, ordocs:
.Tests and linting
pnpm test
and lint the project withpnpm lint