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