mirror of https://github.com/sveltejs/svelte
fix: on teardown, use the last known value for the signal before the set (#15469)
* fix: on teardown, use the last known value for the signal before the se * fix: on teardown, use the last known value for the signal before the se * fix: on teardown, use the last known value for the signal before the se * fix: on teardown, use the last known value for the signal before the se * fix: on teardown, use the last known value for the signal before the se * Update packages/svelte/src/internal/client/reactivity/props.js Co-authored-by: Rich Harris <rich.harris@vercel.com> * Update packages/svelte/src/internal/client/reactivity/props.js Co-authored-by: Rich Harris <rich.harris@vercel.com> * Update packages/svelte/src/internal/client/reactivity/props.js Co-authored-by: Rich Harris <rich.harris@vercel.com> * lint * lint * lint * Update .changeset/sharp-elephants-invite.md --------- Co-authored-by: Rich Harris <rich.harris@vercel.com>pull/15493/head
parent
1cc5bcdc99
commit
110d42062f
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'svelte': minor
|
||||||
|
---
|
||||||
|
|
||||||
|
fix: make values consistent between effects and their cleanup functions
|
@ -0,0 +1,11 @@
|
|||||||
|
<script>
|
||||||
|
import { onDestroy } from 'svelte';
|
||||||
|
|
||||||
|
export let my_prop;
|
||||||
|
|
||||||
|
onDestroy(() => {
|
||||||
|
console.log(my_prop.foo);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{my_prop.foo}
|
@ -0,0 +1,14 @@
|
|||||||
|
import { test } from '../../test';
|
||||||
|
import { flushSync } from 'svelte';
|
||||||
|
|
||||||
|
export default test({
|
||||||
|
async test({ assert, target, logs }) {
|
||||||
|
const [btn1] = target.querySelectorAll('button');
|
||||||
|
|
||||||
|
flushSync(() => {
|
||||||
|
btn1.click();
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.deepEqual(logs, ['bar']);
|
||||||
|
}
|
||||||
|
});
|
@ -0,0 +1,15 @@
|
|||||||
|
<script>
|
||||||
|
import Component from './Component.svelte';
|
||||||
|
|
||||||
|
let value = { foo: 'bar' };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<button
|
||||||
|
onclick={() => {
|
||||||
|
value = undefined;
|
||||||
|
}}>Reset value</button
|
||||||
|
>
|
||||||
|
|
||||||
|
{#if value !== undefined}
|
||||||
|
<Component my_prop={value} />
|
||||||
|
{/if}
|
@ -0,0 +1,5 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
export let ref;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<input bind:this={ref} />
|
@ -0,0 +1,11 @@
|
|||||||
|
import { test } from '../../test';
|
||||||
|
import { flushSync } from 'svelte';
|
||||||
|
|
||||||
|
export default test({
|
||||||
|
async test({ target }) {
|
||||||
|
const [btn1] = target.querySelectorAll('button');
|
||||||
|
|
||||||
|
btn1.click();
|
||||||
|
flushSync();
|
||||||
|
}
|
||||||
|
});
|
@ -0,0 +1,16 @@
|
|||||||
|
<script>
|
||||||
|
import Component from './Component.svelte';
|
||||||
|
let state = { title: 'foo' };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if state}
|
||||||
|
{@const attributes = { title: state.title }}
|
||||||
|
<Component {...attributes} />
|
||||||
|
{/if}
|
||||||
|
<button
|
||||||
|
onclick={() => {
|
||||||
|
state = undefined;
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Del
|
||||||
|
</button>
|
@ -0,0 +1,12 @@
|
|||||||
|
<script>
|
||||||
|
import { onDestroy } from "svelte";
|
||||||
|
export let checked;
|
||||||
|
export let count;
|
||||||
|
onDestroy(() => {
|
||||||
|
console.log(count, checked);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<p>{count}</p>
|
||||||
|
|
||||||
|
<button onclick={()=> count-- }></button>
|
@ -0,0 +1,68 @@
|
|||||||
|
import { test } from '../../test';
|
||||||
|
import { flushSync } from 'svelte';
|
||||||
|
|
||||||
|
export default test({
|
||||||
|
async test({ assert, target, logs }) {
|
||||||
|
const [btn1, btn2, btn3] = target.querySelectorAll('button');
|
||||||
|
let ps = [...target.querySelectorAll('p')];
|
||||||
|
|
||||||
|
for (const p of ps) {
|
||||||
|
assert.equal(p.innerHTML, '0');
|
||||||
|
}
|
||||||
|
|
||||||
|
flushSync(() => {
|
||||||
|
btn1.click();
|
||||||
|
});
|
||||||
|
|
||||||
|
// prop update normally if we are not unmounting
|
||||||
|
for (const p of ps) {
|
||||||
|
assert.equal(p.innerHTML, '1');
|
||||||
|
}
|
||||||
|
|
||||||
|
flushSync(() => {
|
||||||
|
btn3.click();
|
||||||
|
});
|
||||||
|
|
||||||
|
// binding still works and update the value correctly
|
||||||
|
for (const p of ps) {
|
||||||
|
assert.equal(p.innerHTML, '0');
|
||||||
|
}
|
||||||
|
|
||||||
|
flushSync(() => {
|
||||||
|
btn1.click();
|
||||||
|
});
|
||||||
|
|
||||||
|
flushSync(() => {
|
||||||
|
btn1.click();
|
||||||
|
});
|
||||||
|
|
||||||
|
console.warn(logs);
|
||||||
|
|
||||||
|
// the five components guarded by `count < 2` unmount and log
|
||||||
|
assert.deepEqual(logs, [1, true, 1, true, 1, true, 1, true, 1, true]);
|
||||||
|
|
||||||
|
flushSync(() => {
|
||||||
|
btn2.click();
|
||||||
|
});
|
||||||
|
|
||||||
|
// the three components guarded by `show` unmount and log
|
||||||
|
assert.deepEqual(logs, [
|
||||||
|
1,
|
||||||
|
true,
|
||||||
|
1,
|
||||||
|
true,
|
||||||
|
1,
|
||||||
|
true,
|
||||||
|
1,
|
||||||
|
true,
|
||||||
|
1,
|
||||||
|
true,
|
||||||
|
2,
|
||||||
|
true,
|
||||||
|
2,
|
||||||
|
true,
|
||||||
|
2,
|
||||||
|
true
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
});
|
@ -0,0 +1,41 @@
|
|||||||
|
<script>
|
||||||
|
import Component from "./Component.svelte";
|
||||||
|
let show = true;
|
||||||
|
let count = 0;
|
||||||
|
$: spread = { checked: show, count };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<button onclick={()=> count++ }></button>
|
||||||
|
<button onclick={()=> show = !show }></button>
|
||||||
|
|
||||||
|
<!-- count with bind -->
|
||||||
|
{#if count < 2}
|
||||||
|
<Component bind:count bind:checked={show} />
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<!-- spread syntax -->
|
||||||
|
{#if count < 2}
|
||||||
|
<Component {...spread} />
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<!-- normal prop -->
|
||||||
|
{#if count < 2}
|
||||||
|
<Component {count} checked={show} />
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<!-- prop only accessed in destroy -->
|
||||||
|
{#if show}
|
||||||
|
<Component {count} checked={show} />
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<!-- dynamic component -->
|
||||||
|
<svelte:component this={count < 2 ? Component : undefined} {count} checked={show} />
|
||||||
|
|
||||||
|
<!-- dynamic component spread -->
|
||||||
|
<svelte:component this={count < 2 ? Component : undefined} {...spread} />
|
||||||
|
|
||||||
|
<!-- dynamic component with prop only accessed on destroy -->
|
||||||
|
<svelte:component this={show ? Component : undefined} {count} checked={show} />
|
||||||
|
|
||||||
|
<!-- dynamic component with prop only accessed on destroy spread -->
|
||||||
|
<svelte:component this={show ? Component : undefined} {...spread} />
|
Loading…
Reference in new issue