Description
Describe the problem
I'm using a custom made data store with realtime update. In svelte 4, when the value got updated, I was just doing value = value
to refresh different bindings. In svelte 5 it is not possible anymore as before updating bindings, the system check if the value is the same. What more is, inside some of the object, we have our classes that are filled automatically ( think relationships ) and so it seems like svelte is not detecting the change in values.
I'm not sure if I'm clear in what I'm explaining, but basically, I would need something to inform the system to update bindings forcefully.
To be a bit more precise:
The system we have in my company needs to be used without svelte, so we have our own data system. We have so call "Resource" and "ResourceCollection" ( that are basically relationships ). The system handle realtime update accross client using web sockets. To get "informed" of these change we subscribe to the resource. The only way I found to make the refresh working is by doing that ( subscribeAndDo
is internal to our system ) :
let unsub
$effect(() => {
unsub?.unsubscribe?.()
unsub = account.subscribeAndDo(onDestroy, () => {
const newAccount = account
account = null
account = newAccount
})
})
Describe the proposed solution
The goal here is, whenever the props "account" change, we subscribe to it. Then whever something change in "account" the callback will be called. Here, I'm using the "trick" to make sure that svelte update the bindings. It would be great if we can have a $forceUpdate(account) instead. if that make any sense.
Importance
would make my life easier
Activity
dummdidumm commentedon Dec 3, 2024
Why does
account
need to be force-updated exactly? Are there some things in the template that use it that should rerun? If yes, in which way should they rerun?It sounds like you want a solution like this: #10560 (comment)
olivierchatry commentedon Dec 3, 2024
Yes, there is some thing in the template that use it. Looking at the solution you provided, I do not want to wrap things on top of things when a simple force update function would do the job ( seems a lot cleaner and a lot less code ).
olivierchatry commentedon Dec 3, 2024
As far as I can tell my issue if svelte 4 vs svelte 5 is there :
https://github.com/olivierchatry/svelte/blob/2e57612ef495689e628078e988126f057cc2f7a8/packages/svelte/src/internal/client/reactivity/sources.js#L158-L160
webJose commentedon Dec 3, 2024
I think OP wants something like
$state.signal()
that marks the reactive value as changed, which should trigger all effects associated to the signaled state, but without having the value actually changed (skipping the check for equality).olivierchatry commentedon Dec 3, 2024
Thiagolino8 commentedon Dec 3, 2024
Wouldn't it be better if $state.raw behaved like the state declared with let did in V4?
This type of issue appears quite frequently around here
One of the biggest advantages of svelte over other frameworks is precisely the fact that it doesn't need its own ecosystem and works well with vanilla libraries
And one of the factors that contributed the most to this was precisely the fact that it was possible to have reactivity in external objects simply by reassigning them
I agree that it wasn't a good default behavior, but as an optional behavior it was more useful than $state.raw
olivierchatry commentedon Dec 3, 2024
I agree with you, as I have a lot of issues porting my ( quite big ) application. But still, I would rather have a signal function so that I can control myself when to actually trigger reactivity, as some state are actual props, so have a state.raw will mean you need something to declare props as raw as well.
Leonidaz commentedon Dec 3, 2024
It's likely that currently there doesn't exist a straightforward solution but is there a way you could provide a minimal reproduction just client side only if possible? Just so there is total clarity.
client side: Playground
or full-stack sveltekit: Sveltelap
david-plugge commentedon Dec 3, 2024
I feel like If this gets added it would confuse people. To me it sounds like you would be better of writing a wrapping class for your state and using a setter to explicitly run code instead of relying in sveltes reactivity system which is meant to reduce execution time cost by identifying identical values and skipping a rerun.
olivierchatry commentedon Dec 3, 2024
Leonidaz commentedon Dec 3, 2024
I'm thinking that borrowing the idea of an
equality
function option from Angular's signals might be a possible solution for such cases.https://angular.dev/guide/signals#signal-equality-functions
It would only work for
$state.raw()
, and for$state()
at the top level, since it can be a deeply nested proxy (basically only if it's reassigned)Upon set, instead of using Svelte's pre-defined equality function,
equals()
, the provided equality function is used. In this particular case it can just always return false.But for other cases, upon the top level reassignment, the deeply nested properties can be compared and a decision can be made if a change occurred.
It would work with the current
$state.raw()
or$state()
, even with an empty initial state, e.g.$state.raw(undefined, { equal: (prev, value) => false })
. This second parameter would be a pojo, future proofing for any additional options. The usage will not break any of the existing Svelte 5 code as the second parameter is optional.This new option for testing equality would also be helpful for comparing NaN's where in some cases, you'd want NaN's to be equal to each other, like in
Object.is()
olivierchatry commentedon Dec 3, 2024
25 remaining items