Skip to content

{#each} block overwrites objects in state array #10387

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
marc-eggers opened this issue Feb 3, 2024 · 5 comments
Closed

{#each} block overwrites objects in state array #10387

marc-eggers opened this issue Feb 3, 2024 · 5 comments
Labels
Milestone

Comments

@marc-eggers
Copy link

Describe the bug

First off: I'm not entirely sure this is a bug, so if I'm just misunderstanding some intended behaviour here, please let me know.

The src/routes/+page.svelte file in the reproduction repo contains a heavily simplified version of some state logic I've written in a project of mine. The rough breakdown of the setup is as follows:

  • The strat state is an object, which contains an array of steps. The demo contains 3 objects in steps.
  • Each step contains two arrays: players and stickies
  • The view state is an object with a single number value: activeStep
  • The template has an {#each} block, iterating over strat.steps[view.activeStep].players
  • There are 3 buttons, which set view.activeStep to 0, 1, or 2 respectively

A possibly important note: The repro I've provided shows no issues in [email protected] and below. The issue starts appearing at version 5.0.0-next.18.

The presence of this {#each} block alone - nothing else is being done anywhere - leads to some very peculiar behaviour. First off, some definitions: I will be referring to the step active on page load as "initial step", and the one targeted by view.activeStep as "current step".

  • When switching the current step using one of the buttons, the objects in players of the step being activated overwrite those found in the initial step. (The demo only contains a single player object for brevity, but if there are more, all objects in the array get overwritten).
  • For example, when the initial step is 0, and you switch to step 2, the objects in 0 get overwritten and are identical to those in 2. You can tell by the activePlayer.fromStep output in the "UI".
  • If you switch to step 1 after that, the objects in step 0 are now those of step 1.
  • Switching back to 0 does not revert this.
  • If you switch the data source of the {#each} block to stickies instead, you will observe the exact same behaviour, but with the stickies objects, instead.
  • The arrays themselves do not share an identity, only the objects within.

I hope this was a decent description of the issue I encountered. Let me know if there are any questions.

Reproduction

https://stackblitz.com/~/github.com/marc-eggers/svelte-5-bug-repro

Logs

No response

System Info

System:
    OS: macOS 13.2.1
    CPU: (8) arm64 Apple M1
    Memory: 85.89 MB / 8.00 GB
    Shell: 5.8.1 - /bin/zsh
  Binaries:
    Node: 18.16.1 - /usr/local/bin/node
    Yarn: 1.22.19 - /usr/local/bin/yarn
    npm: 9.5.1 - /usr/local/bin/npm
    pnpm: 7.18.2 - ~/Library/pnpm/pnpm
  Browsers:
    Chrome: 121.0.6167.139
    Safari: 16.3
  npmPackages:
    svelte: ^5.0.0-next.45 => 5.0.0-next.45

Severity

blocking an upgrade

@marc-eggers
Copy link
Author

marc-eggers commented Feb 5, 2024

Turns out using a keyed each block fixes this issue, as documented here: https://learn.svelte.dev/tutorial/keyed-each-blocks

I'd still argue that this should be considered a bug, as not properly updating the DOM is one thing, but overwriting objects in state still seems unintended to me.

I will leave this issue open for the time being.

@dummdidumm
Copy link
Member

This is definetly a bug, the array shouldn't get mutated here. Svelte 5 REPL reproduction
Wondering if this is in any way related to #10037 in the sense of that there seems to be some code in the each block logic that mutates the original arrays which it shouldn't. cc @trueadm

@dummdidumm dummdidumm added the bug label Feb 6, 2024
@dummdidumm dummdidumm added this to the 5.0 milestone Feb 6, 2024
@cyantree
Copy link

cyantree commented Feb 7, 2024

I think I stumbled upon the same bug and made another reproduction sample for my usecase:
https://svelte-5-preview.vercel.app/#H4sIAAAAAAAACoWRTW-DMAyG_0qWTSuVENwpIE1aLztshx5LDxDMZi0NKDGTEMp_n8JHKduqwQE79uP4fel5hRIMj449V_kZeMSfmob7nLrGJeYLJAH3ualbLdxJbITGhtJMSSAGijSCYQl7MJQTeMdMMcZYP37cg2XENvnGX05MWyDB2UTsuMk3p6li_b_R4hZa_IuKW6hYoRn9RstbaLlCT9tdpjJVtUoQ1orV6hkkEOwV6c5z7nTbefbi1RQFFUoC7XmoFOj92JykbEkDLNldMgIucbfZTMXh5SdkKm5lOsm_h1x8XO7JzcjZRUgscUnSJRxqRUs0SIiERPGZ9N6wzV-SbDqexeEIuUVofhkbWiPWz2tbFq4bDrOh6xWuBHTBbLrTMcV23T4gc-lRFabZ_ZgXunnX-kOJs1lzzW3WvxzeXgNDGtU7VqNKBLMdvB785T4_1yVWCCWPSLdgT_YbzQYXZT0DAAA=

  • When deleting entry "a" the other entrys will all show subitems "d"
  • When deleting entry "b" the subitem of entry "a" still shows "a" however the subitems of entry "c" and "d" switch to "d"
  • When removing the each block everything is fine (as can be seen in the JSON output on the bottom)

@trueadm
Copy link
Contributor

trueadm commented Feb 8, 2024

These issues should be resolved now.

@dummdidumm
Copy link
Member

fixed by #10422

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

No branches or pull requests

4 participants