mirror of https://github.com/sveltejs/svelte
fix: use `state` instead of `source` in reactive classes (#16239)
* fix: use `state` instead of `source` in reactive classes * fix: use `active_reaction` as indication to use `source` or `state` * fix: cleanup `#initial_reaction` on `teardown` to free memory * fix: use `#source` in `set` too * unused * chore: use WeakRef * use update_version instead of WeakRef in SvelteSet/SvelteMap (#16324) * tidy up * tweak comment to remove active_reaction reference --------- Co-authored-by: Rich Harris <rich.harris@vercel.com>pull/16325/head
parent
140462374a
commit
c9098bcaa0
@ -1,27 +1,101 @@
|
||||
<script>
|
||||
import { SvelteMap } from 'svelte/reactivity';
|
||||
|
||||
let visibleExternal = $state(false);
|
||||
let external = new SvelteMap();
|
||||
const throws = $derived.by(() => {
|
||||
external.set(1, 1);
|
||||
return external;
|
||||
let outside_basic = $state(false);
|
||||
let outside_basic_map = new SvelteMap();
|
||||
const throw_basic = $derived.by(() => {
|
||||
outside_basic_map.set(1, 1);
|
||||
return outside_basic_map;
|
||||
});
|
||||
|
||||
let visibleInternal = $state(false);
|
||||
const works = $derived.by(() => {
|
||||
let internal = new SvelteMap();
|
||||
internal.set(1, 1);
|
||||
return internal;
|
||||
let inside_basic = $state(false);
|
||||
const works_basic = $derived.by(() => {
|
||||
let inside = new SvelteMap();
|
||||
inside.set(1, 1);
|
||||
return inside;
|
||||
});
|
||||
|
||||
let outside_has = $state(false);
|
||||
let outside_has_map = new SvelteMap([[1, 1]]);
|
||||
const throw_has = $derived.by(() => {
|
||||
outside_has_map.has(1);
|
||||
outside_has_map.set(1, 2);
|
||||
return outside_has_map;
|
||||
});
|
||||
|
||||
let inside_has = $state(false);
|
||||
const works_has = $derived.by(() => {
|
||||
let inside = new SvelteMap([[1, 1]]);
|
||||
inside.has(1);
|
||||
inside.set(1, 1);
|
||||
return inside;
|
||||
});
|
||||
|
||||
let outside_get = $state(false);
|
||||
let outside_get_map = new SvelteMap([[1, 1]]);
|
||||
const throw_get = $derived.by(() => {
|
||||
outside_get_map.get(1);
|
||||
outside_get_map.set(1, 2);
|
||||
return outside_get_map;
|
||||
});
|
||||
|
||||
let inside_get = $state(false);
|
||||
const works_get = $derived.by(() => {
|
||||
let inside = new SvelteMap([[1, 1]]);
|
||||
inside.get(1);
|
||||
inside.set(1, 1);
|
||||
return inside;
|
||||
});
|
||||
|
||||
let outside_values = $state(false);
|
||||
let outside_values_map = new SvelteMap([[1, 1]]);
|
||||
const throw_values = $derived.by(() => {
|
||||
outside_values_map.values(1);
|
||||
outside_values_map.set(1, 2);
|
||||
return outside_values_map;
|
||||
});
|
||||
|
||||
let inside_values = $state(false);
|
||||
const works_values = $derived.by(() => {
|
||||
let inside = new SvelteMap([[1, 1]]);
|
||||
inside.values();
|
||||
inside.set(1, 1);
|
||||
return inside;
|
||||
});
|
||||
</script>
|
||||
|
||||
<button onclick={() => (visibleExternal = true)}>external</button>
|
||||
{#if visibleExternal}
|
||||
{throws}
|
||||
<button onclick={() => (outside_basic = true)}>external</button>
|
||||
{#if outside_basic}
|
||||
{throw_basic}
|
||||
{/if}
|
||||
<button onclick={() => (inside_basic = true)}>internal</button>
|
||||
{#if inside_basic}
|
||||
{works_basic}
|
||||
{/if}
|
||||
|
||||
<button onclick={() => (outside_has = true)}>external</button>
|
||||
{#if outside_has}
|
||||
{throw_has}
|
||||
{/if}
|
||||
<button onclick={() => (visibleInternal = true)}>internal</button>
|
||||
{#if visibleInternal}
|
||||
{works}
|
||||
<button onclick={() => (inside_has = true)}>internal</button>
|
||||
{#if inside_has}
|
||||
{works_has}
|
||||
{/if}
|
||||
|
||||
<button onclick={() => (outside_get = true)}>external</button>
|
||||
{#if outside_get}
|
||||
{throw_get}
|
||||
{/if}
|
||||
<button onclick={() => (inside_get = true)}>internal</button>
|
||||
{#if inside_get}
|
||||
{works_get}
|
||||
{/if}
|
||||
|
||||
<button onclick={() => (outside_values = true)}>external</button>
|
||||
{#if outside_values}
|
||||
{throw_values}
|
||||
{/if}
|
||||
<button onclick={() => (inside_values = true)}>internal</button>
|
||||
{#if inside_values}
|
||||
{works_values}
|
||||
{/if}
|
||||
|
@ -1,27 +1,52 @@
|
||||
<script>
|
||||
import { SvelteSet } from 'svelte/reactivity';
|
||||
|
||||
let visibleExternal = $state(false);
|
||||
let external = new SvelteSet();
|
||||
const throws = $derived.by(() => {
|
||||
external.add(1);
|
||||
return external;
|
||||
let outside_basic = $state(false);
|
||||
let outside_basic_set = new SvelteSet();
|
||||
const throws_basic = $derived.by(() => {
|
||||
outside_basic_set.add(1);
|
||||
return outside_basic_set;
|
||||
})
|
||||
|
||||
let visibleInternal = $state(false);
|
||||
const works = $derived.by(() => {
|
||||
let inside_basic = $state(false);
|
||||
const works_basic = $derived.by(() => {
|
||||
let internal = new SvelteSet();
|
||||
internal.add(1);
|
||||
return internal;
|
||||
})
|
||||
|
||||
let outside_has_delete = $state(false);
|
||||
let outside_has_delete_set = new SvelteSet([1]);
|
||||
const throws_has_delete = $derived.by(() => {
|
||||
outside_has_delete_set.has(1);
|
||||
outside_has_delete_set.delete(1);
|
||||
return outside_has_delete_set;
|
||||
})
|
||||
|
||||
let inside_has_delete = $state(false);
|
||||
const works_has_delete = $derived.by(() => {
|
||||
let internal = new SvelteSet([1]);
|
||||
internal.has(1);
|
||||
internal.delete(1);
|
||||
return internal;
|
||||
})
|
||||
</script>
|
||||
|
||||
<button onclick={() => (visibleExternal = true)}>external</button>
|
||||
{#if visibleExternal}
|
||||
{throws}
|
||||
<button onclick={() => (outside_basic = true)}>external</button>
|
||||
{#if outside_basic}
|
||||
{throws_basic}
|
||||
{/if}
|
||||
<button onclick={() => (inside_basic = true)}>internal</button>
|
||||
{#if inside_basic}
|
||||
{works_basic}
|
||||
{/if}
|
||||
|
||||
<button onclick={() => (outside_has_delete = true)}>external</button>
|
||||
{#if outside_has_delete}
|
||||
{throws_has_delete}
|
||||
{/if}
|
||||
<button onclick={() => (visibleInternal = true)}>internal</button>
|
||||
{#if visibleInternal}
|
||||
{works}
|
||||
<button onclick={() => (inside_has_delete = true)}>internal</button>
|
||||
{#if inside_has_delete}
|
||||
{works_has_delete}
|
||||
{/if}
|
||||
|
||||
|
@ -0,0 +1,23 @@
|
||||
import { flushSync } from 'svelte';
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({
|
||||
compileOptions: {
|
||||
dev: true,
|
||||
runes: true
|
||||
},
|
||||
|
||||
test({ assert, target }) {
|
||||
const [button1, button2] = target.querySelectorAll('button');
|
||||
|
||||
assert.throws(() => {
|
||||
button1?.click();
|
||||
flushSync();
|
||||
}, /state_unsafe_mutation/);
|
||||
|
||||
assert.doesNotThrow(() => {
|
||||
button2?.click();
|
||||
flushSync();
|
||||
});
|
||||
}
|
||||
});
|
@ -0,0 +1,26 @@
|
||||
<script>
|
||||
import { Spring } from 'svelte/motion';
|
||||
|
||||
let outside_basic = $state(false);
|
||||
let outside_basic_spring = new Spring(0);
|
||||
const throws_basic = $derived.by(() => {
|
||||
outside_basic_spring.set(1);
|
||||
return outside_basic_spring;
|
||||
})
|
||||
|
||||
let inside_basic = $state(false);
|
||||
const works_basic = $derived.by(() => {
|
||||
let internal = new Spring(0);
|
||||
internal.set(1);
|
||||
return internal;
|
||||
})
|
||||
</script>
|
||||
|
||||
<button onclick={() => (outside_basic = true)}>external</button>
|
||||
{#if outside_basic}
|
||||
{throws_basic}
|
||||
{/if}
|
||||
<button onclick={() => (inside_basic = true)}>internal</button>
|
||||
{#if inside_basic}
|
||||
{works_basic}
|
||||
{/if}
|
@ -0,0 +1,23 @@
|
||||
import { flushSync } from 'svelte';
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({
|
||||
compileOptions: {
|
||||
dev: true,
|
||||
runes: true
|
||||
},
|
||||
|
||||
test({ assert, target }) {
|
||||
const [button1, button2] = target.querySelectorAll('button');
|
||||
|
||||
assert.throws(() => {
|
||||
button1?.click();
|
||||
flushSync();
|
||||
}, /state_unsafe_mutation/);
|
||||
|
||||
assert.doesNotThrow(() => {
|
||||
button2?.click();
|
||||
flushSync();
|
||||
});
|
||||
}
|
||||
});
|
@ -0,0 +1,26 @@
|
||||
<script>
|
||||
import { Tween } from 'svelte/motion';
|
||||
|
||||
let outside_basic = $state(false);
|
||||
let outside_basic_tween = new Tween(0);
|
||||
const throws_basic = $derived.by(() => {
|
||||
outside_basic_tween.set(1);
|
||||
return outside_basic_tween;
|
||||
})
|
||||
|
||||
let inside_basic = $state(false);
|
||||
const works_basic = $derived.by(() => {
|
||||
let internal = new Tween(0);
|
||||
internal.set(1);
|
||||
return internal;
|
||||
})
|
||||
</script>
|
||||
|
||||
<button onclick={() => (outside_basic = true)}>external</button>
|
||||
{#if outside_basic}
|
||||
{throws_basic}
|
||||
{/if}
|
||||
<button onclick={() => (inside_basic = true)}>internal</button>
|
||||
{#if inside_basic}
|
||||
{works_basic}
|
||||
{/if}
|
Loading…
Reference in new issue