fix: ensure untrack correctly retains the active reaction (#15065)

* fix: ensure untrack correctly retains the active reaction

* fix: ensure untrack correctly retains the active reaction
pull/15052/head
Dominic Gannaway 8 months ago committed by GitHub
parent de94159238
commit 2ad519542d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: ensure untrack correctly retains the active reaction

@ -16,7 +16,8 @@ import {
set_is_flushing_effect,
set_signal_status,
untrack,
skip_reaction
skip_reaction,
untracking
} from '../runtime.js';
import {
DIRTY,
@ -43,8 +44,7 @@ import * as e from '../errors.js';
import { DEV } from 'esm-env';
import { define_property } from '../../shared/utils.js';
import { get_next_sibling } from '../dom/operations.js';
import { derived, derived_safe_equal, destroy_derived } from './deriveds.js';
import { legacy_mode_flag } from '../../flags/index.js';
import { derived, destroy_derived } from './deriveds.js';
/**
* @param {'$effect' | '$effect.pre' | '$inspect'} rune
@ -166,7 +166,7 @@ function create_effect(type, fn, sync, push = true) {
* @returns {boolean}
*/
export function effect_tracking() {
if (active_reaction === null) {
if (active_reaction === null || untracking) {
return false;
}

@ -17,7 +17,8 @@ import {
set_derived_sources,
check_dirtiness,
set_is_flushing_effect,
is_flushing_effect
is_flushing_effect,
untracking
} from '../runtime.js';
import { equals, safe_equals } from './equality.js';
import {
@ -148,6 +149,7 @@ export function mutate(source, value) {
export function set(source, value) {
if (
active_reaction !== null &&
!untracking &&
is_runes() &&
(active_reaction.f & (DERIVED | BLOCK_EFFECT)) !== 0 &&
// If the source was created locally within the current derived, then

@ -78,6 +78,8 @@ let dev_effect_stack = [];
/** @type {null | Reaction} */
export let active_reaction = null;
export let untracking = false;
/** @param {null | Reaction} reaction */
export function set_active_reaction(reaction) {
active_reaction = reaction;
@ -423,6 +425,7 @@ export function update_reaction(reaction) {
var previous_skip_reaction = skip_reaction;
var prev_derived_sources = derived_sources;
var previous_component_context = component_context;
var previous_untracking = untracking;
var flags = reaction.f;
new_deps = /** @type {null | Value[]} */ (null);
@ -432,6 +435,7 @@ export function update_reaction(reaction) {
skip_reaction = !is_flushing_effect && (flags & UNOWNED) !== 0;
derived_sources = null;
component_context = reaction.ctx;
untracking = false;
read_version++;
try {
@ -495,6 +499,7 @@ export function update_reaction(reaction) {
skip_reaction = previous_skip_reaction;
derived_sources = prev_derived_sources;
component_context = previous_component_context;
untracking = previous_untracking;
}
}
@ -934,7 +939,7 @@ export function get(signal) {
}
// Register the dependency on the current reaction signal.
if (active_reaction !== null) {
if (active_reaction !== null && !untracking) {
if (derived_sources !== null && derived_sources.includes(signal)) {
e.state_unsafe_local_read();
}
@ -1085,12 +1090,12 @@ export function invalidate_inner_signals(fn) {
* @returns {T}
*/
export function untrack(fn) {
const previous_reaction = active_reaction;
var previous_untracking = untracking;
try {
active_reaction = null;
untracking = true;
return fn();
} finally {
active_reaction = previous_reaction;
untracking = previous_untracking;
}
}

@ -803,6 +803,46 @@ describe('signals', () => {
};
});
test('deriveds containing effects work correctly when used with untrack', () => {
return () => {
let a = render_effect(() => {});
let b = state(0);
let c;
let effects = [];
const destroy = effect_root(() => {
a = render_effect(() => {
c = derived(() => {
$.untrack(() => {
effects.push(
effect(() => {
$.get(b);
})
);
});
$.get(b);
});
$.get(c);
});
});
assert.deepEqual(c!.children?.length, 1);
assert.deepEqual(a.first, a.last);
set(b, 1);
flushSync();
assert.deepEqual(c!.children?.length, 1);
assert.deepEqual(a.first, a.last);
destroy();
assert.deepEqual(a.deriveds, null);
assert.deepEqual(a.first, null);
};
});
test('bigint states update correctly', () => {
return () => {
const count = state(0n);

Loading…
Cancel
Save