Skip to content
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 unstate utility function #9776

Merged
merged 9 commits into from Dec 5, 2023
Merged

feat: add unstate utility function #9776

merged 9 commits into from Dec 5, 2023

Conversation

trueadm
Copy link
Contributor

@trueadm trueadm commented Dec 5, 2023

unstate

To remove reactivity from objects and arrays created with $state, use unstate:

<script>
	import { unstate } from 'svelte';

	let counter = $state({ count: 0 });

	$effect(() => {
		// Will log { count: 0 }
		console.log(unstate(counter));
	});
</script>

This is handy when you want to pass some state to an external library or API that doesn't expect a reactive object – such as structuredClone.

Copy link

changeset-bot bot commented Dec 5, 2023

🦋 Changeset detected

Latest commit: fb73276

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
svelte Patch

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

Copy link

vercel bot commented Dec 5, 2023

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
svelte-5-preview ✅ Ready (Inspect) Visit Preview 💬 Add feedback Dec 5, 2023 7:13pm

@dummdidumm
Copy link
Member

This creates a new object from the given one - is it somehow possible to get the underlying original object instead? If not, this should be called out in the docs.

Co-authored-by: Simon H <5968653+dummdidumm@users.noreply.github.com>
@trueadm
Copy link
Contributor Author

trueadm commented Dec 5, 2023

@dummdidumm We can't return the original object. I've updated the docs.

@dummdidumm
Copy link
Member

Could we add the original object reference to a symbol in the proxy and just take it from there when unwrapping?

Also, what happens if you unwrap something and have a class that itself uses proxy objects? Does unwrap stop at the class boundary (I guess so)? Is there something we can do about this? If not, we need to document that, too. Or we could provide a symbol people can implement on their classes to unwrap manually?

import { UNWRAP_SYMBOL } from 'svelte';

class Foo {
  nestedStuff = $state({ .. });

  [UNWRAP_SYMBOL]: () => {
    // does this even make sense?
    // could we apply this automatically when transforming classes?
    return {
      ...this,
      nestedStuff: unwrap(this.nestedStuff)
   };
  }

@trueadm
Copy link
Contributor Author

trueadm commented Dec 5, 2023

@dummdidumm

Could we add the original object reference to a symbol in the proxy and just take it from there when unwrapping?

I don't get what this gives us? If anything, that means that it won't be reactive anymore. You might want to reactively unstate something.

Also, what happens if you unwrap something and have a class that itself uses proxy objects?

That's a good point. I'll add something for that.

@dummdidumm
Copy link
Member

dummdidumm commented Dec 5, 2023

I don't get what this gives us? If anything, that means that it won't be reactive anymore. You might want to reactively unstate something.

I don't understand how the two are related, and I don't understand what you mean by "you might want to reactivityl unstate something".
What I mean is that when proxying an object because it's $state, we stash away the original object reference on a symbol (maybe using the "this is state" symbol for that). Then, when you unstate, you just take the object from the symbol. That way object identity is preserved.
I guess both solutions have their pros and cons.

@trueadm
Copy link
Contributor Author

trueadm commented Dec 5, 2023

@dummdidumm

That way object identity is preserved.

You can't use that object ever again. We've attached a symbol to that very object and we can't remove the symbol. The symbol prevents the object from being used in structuredClone as it references the internals of Svelte.

@dummdidumm
Copy link
Member

Mhm yeah that makes sense, we also can't delete the symbol because that also affects the proxy. The way around this would be to track this through something else than a property on the object, which would be slower.
Given that you use unstate in situations where you don't want the state to be touched afterwards the behavior of copying kinda makes sense anyway.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants