Skip to content

[Svelte 5] error mutating property of an object and setting the state that is containing it to null/undefined #10000

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

Closed
hawk93 opened this issue Dec 26, 2023 · 2 comments · Fixed by #10175
Assignees

Comments

@hawk93
Copy link

hawk93 commented Dec 26, 2023

Describe the bug

Given a $state that can be an object or undefined and a function that mutates the object and the state at the same time

<script lang="ts">
	let data = $state<{ num: number } | undefined>({ num: 1 });

	function expire() {
		data.num = data.num - 1;
		if (data.num <= 0) data = undefined;
	}
</script>

{#if data}
	<button {expire}>Click</button>
	
	<p>expires in {data.num} click</p>
{/if}

If you try to access an object property in the template you get an error in the console about reading property of null.

You can work around the problem using optional chaining data?.num but considering the property is accessed inside an if block I would expect to not need it

Reproduction

REPL

Logs

Error: Cannot read properties of undefined (reading 'num')

System Info

svelte 5.0.0-next.26

Severity

annoyance

@hawk93 hawk93 changed the title [Svelte 5] mutating state [Svelte 5] error mutating property of an object and setting the state that is containing it to null/undefined Dec 26, 2023
@dummdidumm
Copy link
Member

dummdidumm commented Jan 9, 2024

Because the state is fine-grained, each of these assignments results in a separate effect in the queue, and they are processed in order, causing the bug. This probably can also happen with primitives, although invisibly so. I'm not sure how to solve this other than traversing the effect queue and delete the other effect, which feels wasteful, or to somehow order the effects to execute from top to bottom and not execute effects which are determined to be no longer executable, which seems super tricky because signals don't have a top-down-execution model.

@hawk93
Copy link
Author

hawk93 commented Jan 11, 2024

With primitives you don't get the same error because technically in js you "can" do number / nullish, while you can't access property of nullish values and that breaks the ui.
I understand the problem and why it's not easy prevent this kind of behaviour, but inside an if block where you check for the object existence you don't expect it to be undefined.
The only thing you can do actually is not mutate an object property and the object itself in the same tick, right?

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 a pull request may close this issue.

3 participants