Skip to content

Commit ffb27f6

Browse files
authored
Blockless redux (#10794)
* null out teardown function * add managed effects to effect tree * let the code breathe a bit * bit more * man, that's better * create correct parent-child relationship between if block and its branches * remove unnecessary arg * each blocks already have the correct parent-child relationship so i guess we can get rid of this * simplify * unused import --------- Co-authored-by: Rich Harris <[email protected]>
1 parent 924f061 commit ffb27f6

File tree

3 files changed

+148
-150
lines changed

3 files changed

+148
-150
lines changed

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

Lines changed: 124 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { current_block, execute_effect } from '../../runtime.js';
1010
import { destroy_effect, render_effect } from '../../reactivity/effects.js';
1111
import { trigger_transitions } from '../elements/transitions.js';
1212

13-
/** @returns {import('../../types.js').IfBlock} */
13+
/** @returns {import('#client').IfBlock} */
1414
function create_if_block() {
1515
return {
1616
// alternate transitions
@@ -26,7 +26,7 @@ function create_if_block() {
2626
// effect
2727
e: null,
2828
// parent
29-
p: /** @type {import('../../types.js').Block} */ (current_block),
29+
p: /** @type {import('#client').Block} */ (current_block),
3030
// transition
3131
r: null,
3232
// type
@@ -45,137 +45,157 @@ function create_if_block() {
4545
*/
4646
export function if_block(anchor_node, condition_fn, consequent_fn, alternate_fn) {
4747
const block = create_if_block();
48+
4849
hydrate_block_anchor(anchor_node);
50+
4951
/** Whether or not there was a hydration mismatch. Needs to be a `let` or else it isn't treeshaken out */
5052
let mismatch = false;
5153

52-
/** @type {null | import('../../types.js').TemplateNode | Array<import('../../types.js').TemplateNode>} */
54+
/** @type {null | import('#client').TemplateNode | Array<import('#client').TemplateNode>} */
5355
let consequent_dom = null;
54-
/** @type {null | import('../../types.js').TemplateNode | Array<import('../../types.js').TemplateNode>} */
56+
57+
/** @type {null | import('#client').TemplateNode | Array<import('#client').TemplateNode>} */
5558
let alternate_dom = null;
59+
5660
let has_mounted = false;
61+
5762
/**
58-
* @type {import('../../types.js').Effect | null}
63+
* @type {import('#client').Effect | null}
5964
*/
6065
let current_branch_effect = null;
6166

62-
const if_effect = render_effect(
63-
() => {
64-
const result = !!condition_fn();
65-
if (block.v !== result || !has_mounted) {
66-
block.v = result;
67-
if (has_mounted) {
68-
const consequent_transitions = block.c;
69-
const alternate_transitions = block.a;
70-
if (result) {
71-
if (alternate_transitions === null || alternate_transitions.size === 0) {
72-
execute_effect(alternate_effect);
73-
} else {
74-
trigger_transitions(alternate_transitions, 'out');
75-
}
76-
if (consequent_transitions === null || consequent_transitions.size === 0) {
77-
execute_effect(consequent_effect);
78-
} else {
79-
trigger_transitions(consequent_transitions, 'in');
80-
}
67+
/** @type {import('#client').Effect} */
68+
let consequent_effect;
69+
70+
/** @type {import('#client').Effect} */
71+
let alternate_effect;
72+
73+
const if_effect = render_effect(() => {
74+
const result = !!condition_fn();
75+
76+
if (block.v !== result || !has_mounted) {
77+
block.v = result;
78+
79+
if (has_mounted) {
80+
const consequent_transitions = block.c;
81+
const alternate_transitions = block.a;
82+
83+
if (result) {
84+
if (alternate_transitions === null || alternate_transitions.size === 0) {
85+
execute_effect(alternate_effect);
8186
} else {
82-
if (consequent_transitions === null || consequent_transitions.size === 0) {
83-
execute_effect(consequent_effect);
84-
} else {
85-
trigger_transitions(consequent_transitions, 'out');
86-
}
87-
if (alternate_transitions === null || alternate_transitions.size === 0) {
88-
execute_effect(alternate_effect);
89-
} else {
90-
trigger_transitions(alternate_transitions, 'in');
91-
}
87+
trigger_transitions(alternate_transitions, 'out');
9288
}
93-
} else if (hydrating) {
94-
const comment_text = /** @type {Comment} */ (current_hydration_fragment?.[0])?.data;
95-
if (
96-
!comment_text ||
97-
(comment_text === 'ssr:if:true' && !result) ||
98-
(comment_text === 'ssr:if:false' && result)
99-
) {
100-
// Hydration mismatch: remove everything inside the anchor and start fresh.
101-
// This could happen using when `{#if browser} .. {/if}` in SvelteKit.
102-
remove(current_hydration_fragment);
103-
set_current_hydration_fragment(null);
104-
mismatch = true;
89+
90+
if (consequent_transitions === null || consequent_transitions.size === 0) {
91+
execute_effect(consequent_effect);
10592
} else {
106-
// Remove the ssr:if comment node or else it will confuse the subsequent hydration algorithm
107-
current_hydration_fragment.shift();
93+
trigger_transitions(consequent_transitions, 'in');
94+
}
95+
} else {
96+
if (consequent_transitions === null || consequent_transitions.size === 0) {
97+
execute_effect(consequent_effect);
98+
} else {
99+
trigger_transitions(consequent_transitions, 'out');
100+
}
101+
102+
if (alternate_transitions === null || alternate_transitions.size === 0) {
103+
execute_effect(alternate_effect);
104+
} else {
105+
trigger_transitions(alternate_transitions, 'in');
108106
}
109107
}
110-
has_mounted = true;
111-
}
112-
},
113-
block,
114-
false
115-
);
116-
// Managed effect
117-
const consequent_effect = render_effect(
118-
(
119-
/** @type {any} */ _,
120-
/** @type {import('../../types.js').Effect | null} */ consequent_effect
121-
) => {
122-
const result = block.v;
123-
if (!result && consequent_dom !== null) {
124-
remove(consequent_dom);
125-
consequent_dom = null;
126-
}
127-
if (result && current_branch_effect !== consequent_effect) {
128-
consequent_fn(anchor_node);
129-
if (mismatch && current_branch_effect === null) {
130-
// Set fragment so that Svelte continues to operate in hydration mode
131-
set_current_hydration_fragment([]);
108+
} else if (hydrating) {
109+
const comment_text = /** @type {Comment} */ (current_hydration_fragment?.[0])?.data;
110+
111+
if (
112+
!comment_text ||
113+
(comment_text === 'ssr:if:true' && !result) ||
114+
(comment_text === 'ssr:if:false' && result)
115+
) {
116+
// Hydration mismatch: remove everything inside the anchor and start fresh.
117+
// This could happen using when `{#if browser} .. {/if}` in SvelteKit.
118+
remove(current_hydration_fragment);
119+
set_current_hydration_fragment(null);
120+
mismatch = true;
121+
} else {
122+
// Remove the ssr:if comment node or else it will confuse the subsequent hydration algorithm
123+
current_hydration_fragment.shift();
132124
}
133-
current_branch_effect = consequent_effect;
134-
consequent_dom = block.d;
135125
}
136-
block.d = null;
137-
},
138-
block,
139-
true
140-
);
141-
block.ce = consequent_effect;
142-
// Managed effect
143-
const alternate_effect = render_effect(
144-
(
145-
/** @type {any} */ _,
146-
/** @type {import('../../types.js').Effect | null} */ alternate_effect
147-
) => {
148-
const result = block.v;
149-
if (result && alternate_dom !== null) {
150-
remove(alternate_dom);
151-
alternate_dom = null;
152-
}
153-
if (!result && current_branch_effect !== alternate_effect) {
154-
if (alternate_fn !== null) {
155-
alternate_fn(anchor_node);
126+
127+
has_mounted = true;
128+
}
129+
130+
// create these here so they have the correct parent/child relationship
131+
consequent_effect ??= render_effect(
132+
(/** @type {any} */ _, /** @type {import('#client').Effect | null} */ consequent_effect) => {
133+
const result = block.v;
134+
135+
if (!result && consequent_dom !== null) {
136+
remove(consequent_dom);
137+
consequent_dom = null;
138+
}
139+
140+
if (result && current_branch_effect !== consequent_effect) {
141+
consequent_fn(anchor_node);
142+
if (mismatch && current_branch_effect === null) {
143+
// Set fragment so that Svelte continues to operate in hydration mode
144+
set_current_hydration_fragment([]);
145+
}
146+
current_branch_effect = consequent_effect;
147+
consequent_dom = block.d;
156148
}
157-
if (mismatch && current_branch_effect === null) {
158-
// Set fragment so that Svelte continues to operate in hydration mode
159-
set_current_hydration_fragment([]);
149+
150+
block.d = null;
151+
},
152+
block,
153+
true
154+
);
155+
block.ce = consequent_effect;
156+
157+
alternate_effect ??= render_effect(
158+
(/** @type {any} */ _, /** @type {import('#client').Effect | null} */ alternate_effect) => {
159+
const result = block.v;
160+
161+
if (result && alternate_dom !== null) {
162+
remove(alternate_dom);
163+
alternate_dom = null;
160164
}
161-
current_branch_effect = alternate_effect;
162-
alternate_dom = block.d;
163-
}
164-
block.d = null;
165-
},
166-
block,
167-
true
168-
);
169-
block.ae = alternate_effect;
165+
166+
if (!result && current_branch_effect !== alternate_effect) {
167+
if (alternate_fn !== null) {
168+
alternate_fn(anchor_node);
169+
}
170+
171+
if (mismatch && current_branch_effect === null) {
172+
// Set fragment so that Svelte continues to operate in hydration mode
173+
set_current_hydration_fragment([]);
174+
}
175+
176+
current_branch_effect = alternate_effect;
177+
alternate_dom = block.d;
178+
}
179+
block.d = null;
180+
},
181+
block,
182+
true
183+
);
184+
block.ae = alternate_effect;
185+
}, block);
186+
170187
if_effect.ondestroy = () => {
171188
if (consequent_dom !== null) {
172189
remove(consequent_dom);
173190
}
191+
174192
if (alternate_dom !== null) {
175193
remove(alternate_dom);
176194
}
195+
177196
destroy_effect(consequent_effect);
178197
destroy_effect(alternate_effect);
179198
};
199+
180200
block.e = if_effect;
181201
}

packages/svelte/src/internal/client/reactivity/effects.js

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import {
55
current_effect,
66
current_reaction,
77
destroy_children,
8-
flush_local_render_effects,
98
get,
109
remove_reactions,
1110
schedule_effect,
@@ -42,13 +41,11 @@ function create_effect(type, fn, sync, block = current_block, init = true) {
4241
signal.l = current_effect.l + 1;
4342
}
4443

45-
if ((type & MANAGED) === 0) {
46-
if (current_reaction !== null) {
47-
if (current_reaction.effects === null) {
48-
current_reaction.effects = [signal];
49-
} else {
50-
current_reaction.effects.push(signal);
51-
}
44+
if (current_reaction !== null) {
45+
if (current_reaction.effects === null) {
46+
current_reaction.effects = [signal];
47+
} else {
48+
current_reaction.effects.push(signal);
5249
}
5350
}
5451

@@ -230,5 +227,12 @@ export function destroy_effect(signal) {
230227

231228
signal.teardown?.();
232229
signal.ondestroy?.();
233-
signal.fn = signal.effects = signal.ondestroy = signal.ctx = signal.block = signal.deps = null;
230+
signal.fn =
231+
signal.effects =
232+
signal.teardown =
233+
signal.ondestroy =
234+
signal.ctx =
235+
signal.block =
236+
signal.deps =
237+
null;
234238
}

0 commit comments

Comments
 (0)