Skip to content

Commit 54a17b5

Browse files
committed
only call onchange callbacks once per array mutation
1 parent e42c7cd commit 54a17b5

File tree

2 files changed

+30
-3
lines changed

2 files changed

+30
-3
lines changed

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

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,15 @@ import {
99
object_prototype
1010
} from '../shared/utils.js';
1111
import { check_ownership, widen_ownership } from './dev/ownership.js';
12-
import { source, set, state } from './reactivity/sources.js';
12+
import { source, set, state, set_call_onchange } from './reactivity/sources.js';
1313
import { STATE_SYMBOL, STATE_SYMBOL_METADATA } from './constants.js';
1414
import { UNINITIALIZED } from '../../constants.js';
1515
import * as e from './errors.js';
1616
import { get_stack } from './dev/tracing.js';
1717
import { tracing_mode_flag } from '../flags/index.js';
1818

19+
const array_methods = ['push', 'pop', 'shift', 'unshift', 'splice', 'reverse', 'sort'];
20+
1921
/**
2022
* @template T
2123
* @param {T} value
@@ -168,7 +170,22 @@ export function proxy(value, options, parent = null, prev) {
168170
return v === UNINITIALIZED ? undefined : v;
169171
}
170172

171-
return Reflect.get(target, prop, receiver);
173+
const value = Reflect.get(target, prop, receiver);
174+
175+
if (is_proxied_array && array_methods.includes(/** @type {string} */ (prop))) {
176+
// @ts-expect-error
177+
return (...args) => {
178+
set_call_onchange(false);
179+
const result = value.apply(receiver, args);
180+
set_call_onchange(true);
181+
182+
options?.onchange?.();
183+
184+
return result;
185+
};
186+
}
187+
188+
return value;
172189
},
173190

174191
getOwnPropertyDescriptor(target, prop) {

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,13 @@ export function set_inspect_effects(v) {
4545
inspect_effects = v;
4646
}
4747

48+
let call_onchange = true;
49+
50+
/** @param {boolean} v */
51+
export function set_call_onchange(v) {
52+
call_onchange = v;
53+
}
54+
4855
/**
4956
* @template V
5057
* @param {V} v
@@ -191,7 +198,10 @@ export function internal_set(source, value) {
191198
var old_value = source.v;
192199
source.v = value;
193200
source.wv = increment_write_version();
194-
untrack(() => source.o?.onchange?.());
201+
202+
if (call_onchange) {
203+
untrack(() => source.o?.onchange?.());
204+
}
195205

196206
if (DEV && tracing_mode_flag) {
197207
source.updated = get_stack('UpdatedAt');

0 commit comments

Comments
 (0)