-
-
Notifications
You must be signed in to change notification settings - Fork 4.3k
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
$state.snapshot cause object prototype to be lost #15022
Comments
Classes are not proxied so you don't need to |
@paoloricciuti I see your point. There's a bit different case with Zag, here's part of Svelte Adapter - https://github.com/chakra-ui/zag/blob/b7ad1ef6d1e8f1e381bc838ba719eb7434c2c16e/packages/frameworks/svelte/src/use-service.svelte.ts This adapter is responsive to react for Svelte reactive properties changes: $effect(() => {
const contextSnapshot = $state.snapshot(options?.context)
// @ts-expect-error - svelte typing issue
service.setContext(contextSnapshot)
}) And then apply changes to component's internal state. "Context" in this case is an object that holds "public" state and you're free to change anything you want here. But context properties could contain props of literally any types: scalar types (like number, string, etc.), arrays, objects, functions and of course instances of some class. And since whole context is passed to |
kind of similar to #14988 I wonder if the And if it's not a svelte proxy or any of the handled object types, it just doesn't clone it and returns the value, instead of going ahead with trying If |
That would be a breaking change. We'd have to provide some 2nd argument to indicate this maybe? Tricky one. |
I think there's indeed something missing here because if some library it's using snapshot then you can't do anything about it, even if you use toJSON. But I'm not really sure how we can fix this |
I mean the original post mentions needing to pass this to external libraries. However, if you have a class with |
@paoloricciuti @trueadm maybe it's better to not rely on JSON serialization at all? |
You |
@paoloricciuti here's the part of $state.snapshot clone function: svelte/packages/svelte/src/internal/shared/clone.js Lines 102 to 112 in 973b51d
The problem with |
That might be a bug. Not sure, needs an investigation. |
Yeah but that's what @trueadm was talking about...if you call snapshot you expect the value to not be reactive anymore so we need to recursively snapshot it |
@trueadm @paoloricciuti I see your point, but what if the For example, when you pass an object with a "copy", "clone", or similar method to This would act as a form of user-land reactivity control. |
We considered that. However, if you had a field on your class that was using Feel free to explore changing it and putting it in a PR so we can play around with it. I don't really understand how we can avoid all the problems mentioned in this thread, but maybe there's a clever way you can do it. |
It would really be great to document |
Describe the bug
There's a doc on an official website:
To take a static snapshot of a deeply reactive
$state
proxy, use$state.snapshot
:This is handy when you want to pass some state to an external library or API that doesn’t expect a proxy, such as
structuredClone
.But actually
$state.snapshot
doesn't work in cases when an external library expects to receive an instance of certain class, not just a regular object. Cause $state.snapshot actually makes a copy of object using window.structuredClone API which doesn't keep object prototype, nor private properties: Things that don't work with structured clone .Which makes usage of
$state.snapshot
completely broken with libraries that actually work with classes, not an "anonymous" objects.Reproduction
Here's a minimal code for reproduction:
Another scenario:
There's an awesome headless UI library called Zag, which has date-picker component
Minimal code to use it with Svelte is:
But what if I want to create a simple component that have some reactive props and passes them down to Zag?
So my minimal code will look like this:
Such approach of using Zag could be found in Skeleton UI project for Svelte
Under hood Zag will make context props reactive, using
$effect
+$state.snapshot
runes in Svelte adapter:But Zag expects to get an instance of class CalendarDate (which has some methods, e.g. toDate, compare, etc.) for
min
/max
and an array of instances of CalendarDate forvalue
in this case, but once$state.snapshot
is used to get context props all "type" information about min/max/value get lost.And as a result Zag will fail with an error like:
toDate is not a function
So to work-around it I'll have to create ugly things like this:
Logs
System Info
Severity
blocking all usage of svelte
The text was updated successfully, but these errors were encountered: