Skip to content

Commit 67dc9b2

Browse files
committed
add a way to run code when the current reaction finishes updating
1 parent f261686 commit 67dc9b2

File tree

3 files changed

+30
-5
lines changed

3 files changed

+30
-5
lines changed

packages/svelte/src/internal/client/runtime.js

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
/** @import { Derived, Effect, Reaction, Signal, Source, Value } from '#client' */
22
import { DEV } from 'esm-env';
3-
import { define_property, get_descriptors, get_prototype_of, index_of } from '../shared/utils.js';
3+
import {
4+
define_property,
5+
get_descriptors,
6+
get_prototype_of,
7+
index_of,
8+
run_all
9+
} from '../shared/utils.js';
410
import {
511
destroy_block_effect_children,
612
destroy_effect_children,
@@ -56,6 +62,17 @@ export function set_is_destroying_effect(value) {
5662
is_destroying_effect = value;
5763
}
5864

65+
/** @type {Array<() => void> | null} */
66+
let updated_callbacks = null;
67+
68+
/**
69+
* Run `fn` when the current reaction finishes updating
70+
* @param {() => void} fn
71+
*/
72+
export function onupdated(fn) {
73+
(updated_callbacks ??= []).push(fn);
74+
}
75+
5976
// Handle effect queues
6077

6178
/** @type {Effect[]} */
@@ -265,6 +282,7 @@ export function update_reaction(reaction) {
265282
var previous_reaction_sources = source_ownership;
266283
var previous_component_context = component_context;
267284
var previous_untracking = untracking;
285+
var previous_updated_callbacks = updated_callbacks;
268286

269287
var flags = reaction.f;
270288

@@ -358,6 +376,10 @@ export function update_reaction(reaction) {
358376
} catch (error) {
359377
handle_error(error);
360378
} finally {
379+
if (updated_callbacks !== null) {
380+
run_all(updated_callbacks);
381+
}
382+
361383
new_deps = previous_deps;
362384
skipped_deps = previous_skipped_deps;
363385
untracked_writes = previous_untracked_writes;
@@ -366,6 +388,7 @@ export function update_reaction(reaction) {
366388
source_ownership = previous_reaction_sources;
367389
set_component_context(previous_component_context);
368390
untracking = previous_untracking;
391+
updated_callbacks = previous_updated_callbacks;
369392

370393
reaction.f ^= EFFECT_IS_UPDATING;
371394
}

packages/svelte/src/reactivity/map.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import { DEV } from 'esm-env';
33
import { set, source, state } from '../internal/client/reactivity/sources.js';
44
import { label, tag } from '../internal/client/dev/tracing.js';
5-
import { active_reaction, get } from '../internal/client/runtime.js';
5+
import { active_reaction, get, onupdated } from '../internal/client/runtime.js';
66
import { increment } from './utils.js';
77
import { teardown } from '../internal/client/reactivity/effects.js';
88

@@ -68,9 +68,10 @@ export class SvelteMap extends Map {
6868

6969
if (active_reaction !== null) {
7070
this.#initial_reaction = active_reaction;
71+
7172
// since we only need `initial_reaction` as long as we are in a derived/effect we can
7273
// safely create a teardown function that will reset it to null and allow for GC
73-
teardown(() => {
74+
onupdated(() => {
7475
this.#initial_reaction = null;
7576
});
7677
}

packages/svelte/src/reactivity/set.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import { DEV } from 'esm-env';
33
import { source, set, state } from '../internal/client/reactivity/sources.js';
44
import { label, tag } from '../internal/client/dev/tracing.js';
5-
import { active_reaction, get } from '../internal/client/runtime.js';
5+
import { active_reaction, get, onupdated } from '../internal/client/runtime.js';
66
import { increment } from './utils.js';
77
import { teardown } from '../internal/client/reactivity/effects.js';
88

@@ -63,9 +63,10 @@ export class SvelteSet extends Set {
6363

6464
if (active_reaction !== null) {
6565
this.#initial_reaction = active_reaction;
66+
6667
// since we only need `initial_reaction` as long as we are in a derived/effect we can
6768
// safely create a teardown function that will reset it to null and allow for GC
68-
teardown(() => {
69+
onupdated(() => {
6970
this.#initial_reaction = null;
7071
});
7172
}

0 commit comments

Comments
 (0)