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

Immer JS doesn't work with svelte runes #11781

Closed
crimsonhawk47 opened this issue May 25, 2024 · 5 comments
Closed

Immer JS doesn't work with svelte runes #11781

crimsonhawk47 opened this issue May 25, 2024 · 5 comments

Comments

@crimsonhawk47
Copy link

crimsonhawk47 commented May 25, 2024

Describe the bug

If you try to use the new runes feature like a store and run ImmerJs's produce function on it, you can get a maximum call stack error.

In my example, this seems to only happen if the array is not empty once the produce function is done. For instance, running draft.todos.pop() twice here will work

Reproduction

<script lang="ts">
    import { produce } from "immer";

    const appState = $state({
        todos: [
            {
                title: "q",
                date_added: "asd",
                id: "asd",
            },
            {
                title: "q",
                date_added: "asd",
                id: "asd",
            },
        ],
    });

    let textInput = $state("");
    const onClick = () => {
        const result = produce(appState, (draft) => {
            draft.todos.pop();
            return draft
        });
        console.log(result);
        textInput = "";
    };
</script>

<h1>Welcome to SvelteKit</h1>
<input bind:value={textInput} />
<button onclick={onClick}>Submit</button>
{#each appState.todos as todo}
    <p>{todo.title}</p>
{/each}
<p>
    Visit <a href="https://kit.svelte.dev">kit.svelte.dev</a> to read the documentation
</p>

Logs

Uncaught RangeError: Maximum call stack size exceeded
    at get (chunk-7ZZEPC7R.js?v=7cbabef2:1900:13)
    at Object.ownKeys (chunk-7ZZEPC7R.js?v=7cbabef2:1125:5)
    at Reflect.ownKeys (<anonymous>)
    at each (immer.js?v=7cbabef2:78:13)
    at finalize (immer.js?v=7cbabef2:268:5)
    at finalizeProperty (immer.js?v=7cbabef2:326:5)
    at immer.js?v=7cbabef2:270:28
    at immer.js?v=7cbabef2:79:7
    at Array.forEach (<anonymous>)
    at each (immer.js?v=7cbabef2:78:26)

System Info

System:
    OS: macOS 14.1
    CPU: (10) arm64 Apple M1 Max
    Memory: 192.66 MB / 64.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 16.13.2 - ~/.nvm/versions/node/v16.13.2/bin/node
    Yarn: 1.22.18 - ~/.nvm/versions/node/v16.13.2/bin/yarn
    npm: 8.1.2 - ~/.nvm/versions/node/v16.13.2/bin/npm
  Browsers:
    Chrome: 125.0.6422.78
    Safari: 17.1

Severity

annoyance

@crimsonhawk47 crimsonhawk47 changed the title Immer JS doesn't work with svelte runes when using a getter Immer JS doesn't work with svelte runes May 25, 2024
@crimsonhawk47
Copy link
Author

To narrow this down more, if you simplify the code to do NOTHING.

const result = produce(appState, (draft) => {
            console.log("woah")
        });

You will still get an error

'getOwnPropertyDescriptor' on proxy: trap returned descriptor for property 'todos' that is incompatible with the existing property in the proxy target
    at Function.entries (<anonymous>)
    at freeze (immer.js?v=7cbabef2:168:12)
    at maybeFreeze (immer.js?v=7cbabef2:333:5)
    at finalize (immer.js?v=7cbabef2:277:5)
    at processResult (immer.js?v=7cbabef2:255:14)
    at Immer2.produce (immer.js?v=7cbabef2:551:16)
    at HTMLButtonElement.onClick (+page.svelte:23:24)
    at next (chunk-33KSVKAN.js?v=7cbabef2:346:14)
    at chunk-33KSVKAN.js?v=7cbabef2:358:25
    at yield_updates (chunk-7ZZEPC7R.js?v=7cbabef2:1868:12)

This does not happen if you remove $state and make it a raw object

@crimsonhawk47
Copy link
Author

Looks like the solution is to use $state.snapshot per the docs.

const result = produce($state.snapshot(appState), (draft) => {
    console.log("woah")
});

You can close this unless action needs to be taken here

@dummdidumm
Copy link
Member

Since immer is designed to handle immutable state, another possibility would be $state.frozen, but it likely wouldn't work when trying to mutate top level properties of the object because it's frozen. Mhm..

@brunnerh
Copy link
Member

It works with frozen, the whole point of immer is to never modify objects at all but to replace them if anything changes.

@dummdidumm
Copy link
Member

Oh right, they're doing a proxy themselves etc.

Yeah, $state.frozen is the way then - closing since there are ways to solve this.

@dummdidumm dummdidumm closed this as not planned Won't fix, can't repro, duplicate, stale May 26, 2024
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

No branches or pull requests

3 participants