fix: only call `onchange` once for array mutations (#15073)

* only call onchange callbacks once per array mutation

* fix

* fix
pull/15579/head
Rich Harris 8 months ago committed by GitHub
parent e42c7cd567
commit 807ffbb633
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -9,13 +9,15 @@ import {
object_prototype
} from '../shared/utils.js';
import { check_ownership, widen_ownership } from './dev/ownership.js';
import { source, set, state } from './reactivity/sources.js';
import { source, set, state, batch_onchange } from './reactivity/sources.js';
import { STATE_SYMBOL, STATE_SYMBOL_METADATA } from './constants.js';
import { UNINITIALIZED } from '../../constants.js';
import * as e from './errors.js';
import { get_stack } from './dev/tracing.js';
import { tracing_mode_flag } from '../flags/index.js';
const array_methods = ['push', 'pop', 'shift', 'unshift', 'splice', 'reverse', 'sort'];
/**
* @template T
* @param {T} value
@ -168,7 +170,13 @@ export function proxy(value, options, parent = null, prev) {
return v === UNINITIALIZED ? undefined : v;
}
return Reflect.get(target, prop, receiver);
v = Reflect.get(target, prop, receiver);
if (is_proxied_array && array_methods.includes(/** @type {string} */ (prop))) {
return batch_onchange(v);
}
return v;
},
getOwnPropertyDescriptor(target, prop) {

@ -45,6 +45,32 @@ export function set_inspect_effects(v) {
inspect_effects = v;
}
/** @type {null | Set<() => void>} */
let onchange_batch = null;
/**
* @param {Function} fn
*/
export function batch_onchange(fn) {
// @ts-expect-error
return function (...args) {
let previous_onchange_batch = onchange_batch;
try {
onchange_batch = new Set();
// @ts-expect-error
return fn.apply(this, args);
} finally {
for (const onchange of /** @type {Set<() => void>} */ (onchange_batch)) {
onchange();
}
onchange_batch = previous_onchange_batch;
}
};
}
/**
* @template V
* @param {V} v
@ -191,7 +217,15 @@ export function internal_set(source, value) {
var old_value = source.v;
source.v = value;
source.wv = increment_write_version();
untrack(() => source.o?.onchange?.());
var onchange = source.o?.onchange;
if (onchange) {
if (onchange_batch) {
onchange_batch.add(onchange);
} else {
onchange();
}
}
if (DEV && tracing_mode_flag) {
source.updated = get_stack('UpdatedAt');

Loading…
Cancel
Save