sveltejs / svelte

Cybernetically enhanced web apps
https://svelte.dev
MIT License
78.04k stars 4.08k forks source link

[svelte5] use $state infinite loop bug > effect_update_depth_exceeded #12117

Closed Neptunium1129 closed 2 months ago

Neptunium1129 commented 2 months ago

Describe the bug

my code is a loop bug when using the state function. this is code is "https://github.com/flekschas/svelte-simple-modal" migrate rune test mode.

image

let modalState = $state(defaultState);  //[WARING REPL LOOP]

image

let modalState = defaultState; // no problem but,  $state waring tooltip open

Reproduction

REPL

Logs

No response

System Info

System:
    OS: Windows 10 10.0.19045
    CPU: (8) x64 Genuine Intel(R) CPU 0000 @ 1.60GHz
    Memory: 7.60 GB / 15.92 GB
  Binaries:
    Node: 20.14.0 - C:\Program Files\nodejs\node.EXE
    Yarn: 1.22.22 - ~\AppData\Roaming\npm\yarn.CMD
    npm: 10.7.0 - C:\Program Files\nodejs\npm.CMD
  Browsers:
    Chrome: 125.0.6422.142
    Edge: Chromium (125.0.2535.92)
    Internet Explorer: 11.0.19041.4355
  npmPackages:
    svelte: 5.0.0-next.162

Severity

annoyance

paoloricciuti commented 2 months ago

Can you provide a more minimal reproduction or at least a list of steps to reproduce and where to look at?

Neptunium1129 commented 2 months ago

Can you provide a more minimal reproduction or at least a list of steps to reproduce and where to look at?

change code ModalLib.svelte

line 308

//let modalState = $state(defaultState);
let modalState = defaultState;

like this 
let modalState = $state(defaultState);
//let modalState = defaultState;
7nik commented 2 months ago

In $effect you do showPopup(modalObj) which calls open which does

  modalState = { ...defaultState, ...options };
  updateStyleTransition(); // reads `modalState`

and congratulations, you got a dependency loop 🎉

Solution: wrap call of either showPopup (preferable) or updateStyleTransition with the untrack.

If modalState isn't modified after the assignment, you can just disable that warning.

Neptunium1129 commented 2 months ago

In $effect you do showPopup(modalObj) which calls open which does

  modalState = { ...defaultState, ...options };
  updateStyleTransition(); // reads `modalState`

and congratulations, you got a dependency loop 🎉

Solution: wrap call of either showPopup (preferable) or updateStyleTransition with the untrack.

If modalState isn't modified after the assignment, you can just disable that warning.

 $effect(()=>{
        if(modalObj != null){
            const a = untrack(() => {showPopup(modalObj)})
        }
    });  

This is exactly the code I wanted. Thanks for the advice!