File tree Expand file tree Collapse file tree 6 files changed +112
-10
lines changed
compiler/phases/3-transform/client/visitors
tests/runtime-runes/samples/snippet-reactive-args Expand file tree Collapse file tree 6 files changed +112
-10
lines changed Original file line number Diff line number Diff line change
1
+ ---
2
+ ' svelte ' : patch
3
+ ---
4
+
5
+ fix: prevent reactive snippet from reinitializing unnecessarily
Original file line number Diff line number Diff line change @@ -1734,18 +1734,20 @@ export const template_visitors = {
1734
1734
if ( node . argument ) {
1735
1735
args . push ( b . thunk ( /** @type {import('estree').Expression } */ ( context . visit ( node . argument ) ) ) ) ;
1736
1736
}
1737
- const snippet_function = /** @type {import('estree').Expression } */ (
1737
+
1738
+ let snippet_function = /** @type {import('estree').Expression } */ (
1738
1739
context . visit ( node . expression )
1739
1740
) ;
1740
- const init = b . call (
1741
- context . state . options . dev ? b . call ( '$.validate_snippet' , snippet_function ) : snippet_function ,
1742
- ...args
1743
- ) ;
1741
+ if ( context . state . options . dev ) {
1742
+ snippet_function = b . call ( '$.validate_snippet' , snippet_function ) ;
1743
+ }
1744
1744
1745
1745
if ( is_reactive ) {
1746
- context . state . init . push ( b . stmt ( b . call ( '$.snippet_effect' , b . thunk ( init ) ) ) ) ;
1746
+ context . state . init . push (
1747
+ b . stmt ( b . call ( '$.snippet_effect' , b . thunk ( snippet_function ) , ...args ) )
1748
+ ) ;
1747
1749
} else {
1748
- context . state . init . push ( b . stmt ( init ) ) ;
1750
+ context . state . init . push ( b . stmt ( b . call ( snippet_function , ... args ) ) ) ;
1749
1751
}
1750
1752
} ,
1751
1753
AnimateDirective ( node , { state, visit } ) {
Original file line number Diff line number Diff line change @@ -3170,13 +3170,18 @@ export function sanitize_slots(props) {
3170
3170
}
3171
3171
3172
3172
/**
3173
- * @param {() => void } create_snippet
3173
+ * @param {() => Function } get_snippet
3174
+ * @param {Node } node
3175
+ * @param {() => any } args
3174
3176
* @returns {void }
3175
3177
*/
3176
- export function snippet_effect ( create_snippet ) {
3178
+ export function snippet_effect ( get_snippet , node , args ) {
3177
3179
const block = create_snippet_block ( ) ;
3178
3180
render_effect ( ( ) => {
3179
- create_snippet ( ) ;
3181
+ // Only rerender when the snippet function itself changes,
3182
+ // not when an eagerly-read prop inside the snippet function changes
3183
+ const snippet = get_snippet ( ) ;
3184
+ untrack ( ( ) => snippet ( node , args ) ) ;
3180
3185
return ( ) => {
3181
3186
if ( block . d !== null ) {
3182
3187
remove ( block . d ) ;
Original file line number Diff line number Diff line change
1
+ import { test } from '../../test' ;
2
+
3
+ export default test ( {
4
+ html : `
5
+ <p>snippet: 0</p>
6
+ <button>toggle</button>
7
+ <button>increase count</button>
8
+ ` ,
9
+ props : {
10
+ get log ( ) {
11
+ return [ ] ;
12
+ }
13
+ } ,
14
+
15
+ async test ( { assert, target, component } ) {
16
+ const [ toggle , increment ] = target . querySelectorAll ( 'button' ) ;
17
+
18
+ await increment ?. click ( ) ;
19
+ assert . htmlEqual (
20
+ target . innerHTML ,
21
+ `
22
+ <p>snippet: 1</p>
23
+ <button>toggle</button>
24
+ <button>increase count</button>
25
+ `
26
+ ) ;
27
+ assert . deepEqual ( component . log , [ ] ) ;
28
+
29
+ await toggle ?. click ( ) ;
30
+ assert . htmlEqual (
31
+ target . innerHTML ,
32
+ `
33
+ <p>component: 1</p>
34
+ <button>toggle</button>
35
+ <button>increase count</button>
36
+ `
37
+ ) ;
38
+ assert . deepEqual ( component . log , [ 1 ] ) ;
39
+
40
+ await increment ?. click ( ) ;
41
+ assert . htmlEqual (
42
+ target . innerHTML ,
43
+ `
44
+ <p>component: 2</p>
45
+ <button>toggle</button>
46
+ <button>increase count</button>
47
+ `
48
+ ) ;
49
+ assert . deepEqual ( component . log , [ 1 ] ) ;
50
+
51
+ await toggle ?. click ( ) ;
52
+ assert . htmlEqual (
53
+ target . innerHTML ,
54
+ `
55
+ <p>snippet: 2</p>
56
+ <button>toggle</button>
57
+ <button>increase count</button>
58
+ `
59
+ ) ;
60
+ assert . deepEqual ( component . log , [ 1 ] ) ;
61
+ }
62
+ } ) ;
Original file line number Diff line number Diff line change
1
+ <script >
2
+ let { count, log } = $props ();
3
+ log .push (count);
4
+ </script >
5
+
6
+ <p >component: {count }</p >
Original file line number Diff line number Diff line change
1
+ <script >
2
+ import Inner from " ./inner.svelte" ;
3
+
4
+ let { log } = $props ();
5
+
6
+ let count = $state (0 );
7
+ let show_foo = $state (true );
8
+ let snippet = $derived (show_foo ? foo : bar);
9
+ </script >
10
+
11
+ {#snippet foo ({count })}
12
+ <p >snippet: {count }</p >
13
+ {/ snippet }
14
+
15
+ {#snippet bar (props )}
16
+ <Inner {...props }></Inner >
17
+ {/ snippet }
18
+
19
+ {@render snippet ({ count , log })}
20
+
21
+ <button onclick ={() => show_foo = ! show_foo }>toggle</button >
22
+ <button onclick ={() => count ++ }>increase count</button >
You can’t perform that action at this time.
0 commit comments