Skip to content

Commit 15a8518

Browse files
authored
fix: ensure each blocks properly handle $state.frozen objects in prod (#12305)
* fix: ensure each blocks properly handle $state.frozen objects in prod * fix: ensure each blocks properly handle $state.frozen objects in prod
1 parent bc32b7c commit 15a8518

File tree

4 files changed

+47
-2
lines changed

4 files changed

+47
-2
lines changed

.changeset/long-carrots-sneeze.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: ensure each blocks properly handle $state.frozen objects in prod

packages/svelte/src/internal/client/dom/blocks/each.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import {
2828
} from '../../reactivity/effects.js';
2929
import { source, mutable_source, set } from '../../reactivity/sources.js';
3030
import { is_array, is_frozen } from '../../utils.js';
31-
import { INERT, STATE_SYMBOL } from '../../constants.js';
31+
import { INERT, STATE_FROZEN_SYMBOL, STATE_SYMBOL } from '../../constants.js';
3232
import { queue_micro_task } from '../task.js';
3333
import { current_effect } from '../../runtime.js';
3434

@@ -137,7 +137,12 @@ export function each(anchor, flags, get_collection, get_key, render_fn, fallback
137137
// If we are working with an array that isn't proxied or frozen, then remove strict equality and ensure the items
138138
// are treated as reactive, so they get wrapped in a signal.
139139
var flags = state.flags;
140-
if ((flags & EACH_IS_STRICT_EQUALS) !== 0 && !is_frozen(array) && !(STATE_SYMBOL in array)) {
140+
if (
141+
(flags & EACH_IS_STRICT_EQUALS) !== 0 &&
142+
!is_frozen(array) &&
143+
!(STATE_FROZEN_SYMBOL in array) &&
144+
!(STATE_SYMBOL in array)
145+
) {
141146
flags ^= EACH_IS_STRICT_EQUALS;
142147

143148
// Additionally if we're in an keyed each block, we'll need ensure the items are all wrapped in signals.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { flushSync } from 'svelte';
2+
import { test } from '../../test';
3+
4+
export default test({
5+
// TODO: need to force DEV to be false for runtime somehow
6+
async test({ assert, target, logs }) {
7+
const [btn1] = target.querySelectorAll('button');
8+
9+
assert.equal(logs.length, 3);
10+
11+
logs.length = 0;
12+
13+
flushSync(() => {
14+
btn1.click();
15+
});
16+
17+
assert.equal(logs.length, 1);
18+
}
19+
});
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<script>
2+
let frozen_items = $state.frozen([
3+
{id: 0, text: 'a'},
4+
{id: 1, text: 'b'},
5+
{id: 2, text: 'c'}
6+
])
7+
</script>
8+
9+
{#each frozen_items as item (item.id)}
10+
{console.log(item.text)}
11+
{item.text}
12+
{/each}
13+
14+
<button onclick={() => {
15+
frozen_items = [...frozen_items, {id: 3, text: 'd'}]
16+
}}></button>

0 commit comments

Comments
 (0)