fix: populate `this.#sources` when constructing reactive map (#11915)

* fix: populate `this.#sources` when constructing reactive map

* populate sources in first #read_all

* use increment helper

* use numbers instead of symbols

* make forEach work
pull/11899/head
Rich Harris 1 year ago committed by GitHub
parent 862949d22a
commit b1cbfc3d38
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -2,4 +2,4 @@
'svelte': patch 'svelte': patch
--- ---
fix: increment version when creating new source in Map.get or Map.has fix: populate `this.#sources` when constructing reactive map

@ -1,7 +1,7 @@
import { DEV } from 'esm-env'; import { DEV } from 'esm-env';
import { source, set } from '../internal/client/reactivity/sources.js'; import { source, set } from '../internal/client/reactivity/sources.js';
import { get } from '../internal/client/runtime.js'; import { get } from '../internal/client/runtime.js';
import { UNINITIALIZED } from '../constants.js'; import { increment } from './utils.js';
/** /**
* @template K * @template K
@ -9,7 +9,7 @@ import { UNINITIALIZED } from '../constants.js';
* @extends {Map<K, V>} * @extends {Map<K, V>}
*/ */
export class ReactiveMap extends Map { export class ReactiveMap extends Map {
/** @type {Map<K, import('#client').Source<symbol>>} */ /** @type {Map<K, import('#client').Source<number>>} */
#sources = new Map(); #sources = new Map();
#version = source(0); #version = source(0);
#size = source(0); #size = source(0);
@ -31,10 +31,6 @@ export class ReactiveMap extends Map {
} }
} }
#increment_version() {
set(this.#version, this.#version.v + 1);
}
/** @param {K} key */ /** @param {K} key */
has(key) { has(key) {
var sources = this.#sources; var sources = this.#sources;
@ -43,9 +39,8 @@ export class ReactiveMap extends Map {
if (s === undefined) { if (s === undefined) {
var ret = super.get(key); var ret = super.get(key);
if (ret !== undefined) { if (ret !== undefined) {
s = source(Symbol()); s = source(0);
sources.set(key, s); sources.set(key, s);
this.#increment_version();
} else { } else {
// We should always track the version in case // We should always track the version in case
// the Set ever gets this value in the future. // the Set ever gets this value in the future.
@ -63,9 +58,8 @@ export class ReactiveMap extends Map {
* @param {any} [this_arg] * @param {any} [this_arg]
*/ */
forEach(callbackfn, this_arg) { forEach(callbackfn, this_arg) {
get(this.#version); this.#read_all();
super.forEach(callbackfn, this_arg);
return super.forEach(callbackfn, this_arg);
} }
/** @param {K} key */ /** @param {K} key */
@ -76,9 +70,8 @@ export class ReactiveMap extends Map {
if (s === undefined) { if (s === undefined) {
var ret = super.get(key); var ret = super.get(key);
if (ret !== undefined) { if (ret !== undefined) {
s = source(Symbol()); s = source(0);
sources.set(key, s); sources.set(key, s);
this.#increment_version();
} else { } else {
// We should always track the version in case // We should always track the version in case
// the Set ever gets this value in the future. // the Set ever gets this value in the future.
@ -102,11 +95,11 @@ export class ReactiveMap extends Map {
var res = super.set(key, value); var res = super.set(key, value);
if (s === undefined) { if (s === undefined) {
sources.set(key, source(Symbol())); sources.set(key, source(0));
set(this.#size, super.size); set(this.#size, super.size);
this.#increment_version(); increment(this.#version);
} else if (prev_res !== value) { } else if (prev_res !== value) {
set(s, Symbol()); increment(s);
} }
return res; return res;
@ -121,8 +114,8 @@ export class ReactiveMap extends Map {
if (s !== undefined) { if (s !== undefined) {
sources.delete(key); sources.delete(key);
set(this.#size, super.size); set(this.#size, super.size);
set(s, UNINITIALIZED); set(s, -1);
this.#increment_version(); increment(this.#version);
} }
return res; return res;
@ -134,9 +127,9 @@ export class ReactiveMap extends Map {
if (super.size !== 0) { if (super.size !== 0) {
set(this.#size, 0); set(this.#size, 0);
for (var s of sources.values()) { for (var s of sources.values()) {
set(s, UNINITIALIZED); set(s, -1);
} }
this.#increment_version(); increment(this.#version);
sources.clear(); sources.clear();
} }
super.clear(); super.clear();
@ -144,6 +137,16 @@ export class ReactiveMap extends Map {
#read_all() { #read_all() {
get(this.#version); get(this.#version);
var sources = this.#sources;
if (this.#size.v !== sources.size) {
for (var key of super.keys()) {
if (!sources.has(key)) {
sources.set(key, source(0));
}
}
}
for (var [, s] of this.#sources) { for (var [, s] of this.#sources) {
get(s); get(s);
} }

@ -1,6 +1,7 @@
import { DEV } from 'esm-env'; import { DEV } from 'esm-env';
import { source, set } from '../internal/client/reactivity/sources.js'; import { source, set } from '../internal/client/reactivity/sources.js';
import { get } from '../internal/client/runtime.js'; import { get } from '../internal/client/runtime.js';
import { increment } from './utils.js';
var read_methods = ['forEach', 'isDisjointFrom', 'isSubsetOf', 'isSupersetOf']; var read_methods = ['forEach', 'isDisjointFrom', 'isSubsetOf', 'isSupersetOf'];
var set_like_methods = ['difference', 'intersection', 'symmetricDifference', 'union']; var set_like_methods = ['difference', 'intersection', 'symmetricDifference', 'union'];
@ -63,10 +64,6 @@ export class ReactiveSet extends Set {
} }
} }
#increment_version() {
set(this.#version, this.#version.v + 1);
}
/** @param {T} value */ /** @param {T} value */
has(value) { has(value) {
var sources = this.#sources; var sources = this.#sources;
@ -98,7 +95,7 @@ export class ReactiveSet extends Set {
if (s === undefined) { if (s === undefined) {
sources.set(value, source(true)); sources.set(value, source(true));
set(this.#size, super.size); set(this.#size, super.size);
this.#increment_version(); increment(this.#version);
} else { } else {
set(s, true); set(s, true);
} }
@ -116,7 +113,7 @@ export class ReactiveSet extends Set {
sources.delete(value); sources.delete(value);
set(this.#size, super.size); set(this.#size, super.size);
set(s, false); set(s, false);
this.#increment_version(); increment(this.#version);
} }
return res; return res;
@ -130,7 +127,7 @@ export class ReactiveSet extends Set {
for (var s of sources.values()) { for (var s of sources.values()) {
set(s, false); set(s, false);
} }
this.#increment_version(); increment(this.#version);
sources.clear(); sources.clear();
} }
super.clear(); super.clear();

@ -1,5 +1,6 @@
import { source, set } from '../internal/client/reactivity/sources.js'; import { source, set } from '../internal/client/reactivity/sources.js';
import { get } from '../internal/client/runtime.js'; import { get } from '../internal/client/runtime.js';
import { increment } from './utils.js';
const REPLACE = Symbol(); const REPLACE = Symbol();
@ -155,10 +156,6 @@ export class ReactiveURL extends URL {
export class ReactiveURLSearchParams extends URLSearchParams { export class ReactiveURLSearchParams extends URLSearchParams {
#version = source(0); #version = source(0);
#increment_version() {
set(this.#version, this.#version.v + 1);
}
/** /**
* @param {URLSearchParams} params * @param {URLSearchParams} params
*/ */
@ -171,7 +168,7 @@ export class ReactiveURLSearchParams extends URLSearchParams {
super.append(key, value); super.append(key, value);
} }
this.#increment_version(); increment(this.#version);
} }
/** /**
@ -180,7 +177,7 @@ export class ReactiveURLSearchParams extends URLSearchParams {
* @returns {void} * @returns {void}
*/ */
append(name, value) { append(name, value) {
this.#increment_version(); increment(this.#version);
return super.append(name, value); return super.append(name, value);
} }
@ -190,7 +187,7 @@ export class ReactiveURLSearchParams extends URLSearchParams {
* @returns {void} * @returns {void}
*/ */
delete(name, value) { delete(name, value) {
this.#increment_version(); increment(this.#version);
return super.delete(name, value); return super.delete(name, value);
} }
@ -233,12 +230,12 @@ export class ReactiveURLSearchParams extends URLSearchParams {
* @returns {void} * @returns {void}
*/ */
set(name, value) { set(name, value) {
this.#increment_version(); increment(this.#version);
return super.set(name, value); return super.set(name, value);
} }
sort() { sort() {
this.#increment_version(); increment(this.#version);
return super.sort(); return super.sort();
} }

@ -1,3 +1,5 @@
import { set } from '../internal/client/reactivity/sources.js';
/** /**
* @template T * @template T
* @template U * @template U
@ -27,3 +29,8 @@ export function map(iterable, fn, name) {
function get_this() { function get_this() {
return this; return this;
} }
/** @param {import('#client').Source<number>} source */
export function increment(source) {
set(source, source.v + 1);
}

Loading…
Cancel
Save