Skip to content

Commit c3836a8

Browse files
committed
adds reconcileWithKeys
1 parent e4b2c66 commit c3836a8

File tree

2 files changed

+68
-8
lines changed

2 files changed

+68
-8
lines changed

packages/solid/store/src/modifiers.ts

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,20 @@ export type ReconcileOptions = {
66
key?: string | null;
77
merge?: boolean;
88
};
9+
export type ReconcileWithKeysOptions = {
10+
keys?: object | null;
11+
merge?: boolean;
12+
};
13+
const emptyKeys = /* #__PURE__*/ Object.create(null);
914

1015
function applyState(
1116
target: any,
1217
parent: any,
1318
property: PropertyKey,
1419
merge: boolean | undefined,
15-
key: string | null
20+
key: string | null,
21+
keys: object | null,
22+
useKeys: boolean | null
1623
) {
1724
const previous = parent[property];
1825
if (target === previous) return;
@@ -43,7 +50,7 @@ function applyState(
4350
(key && previous[start] && target[start] && previous[start][key] === target[start][key]));
4451
start++
4552
) {
46-
applyState(target[start], previous, start, merge, key);
53+
applyState(target[start], previous, start, merge, key, keys, useKeys);
4754
}
4855

4956
const temp = new Array(target.length),
@@ -65,7 +72,7 @@ function applyState(
6572
for (j = start; j <= newEnd; j++) setProperty(previous, j, target[j]);
6673
for (; j < target.length; j++) {
6774
setProperty(previous, j, temp[j]);
68-
applyState(target[j], previous, j, merge, key);
75+
applyState(target[j], previous, j, merge, key, keys, useKeys);
6976
}
7077
if (previous.length > target.length) setProperty(previous, "length", target.length);
7178
return;
@@ -95,12 +102,12 @@ function applyState(
95102
for (j = start; j < target.length; j++) {
96103
if (j in temp) {
97104
setProperty(previous, j, temp[j]);
98-
applyState(target[j], previous, j, merge, key);
105+
applyState(target[j], previous, j, merge, key, keys, useKeys);
99106
} else setProperty(previous, j, target[j]);
100107
}
101108
} else {
102109
for (let i = 0, len = target.length; i < len; i++) {
103-
applyState(target[i], previous, i, merge, key);
110+
applyState(target[i], previous, i, merge, key, keys, useKeys);
104111
}
105112
}
106113
if (previous.length > target.length) setProperty(previous, "length", target.length);
@@ -109,7 +116,15 @@ function applyState(
109116

110117
const targetKeys = Object.keys(target);
111118
for (let i = 0, len = targetKeys.length; i < len; i++) {
112-
applyState(target[targetKeys[i]], previous, targetKeys[i], merge, key);
119+
applyState(
120+
target[targetKeys[i]],
121+
previous,
122+
targetKeys[i],
123+
merge,
124+
!useKeys ? key : isArray ? (keys || emptyKeys)._key : keys[targetKeys[i]]?._key,
125+
!useKeys ? null : isArray ? keys : keys[targetKeys[i]] || emptyKeys,
126+
useKeys
127+
);
113128
}
114129
const previousKeys = Object.keys(previous);
115130
for (let i = 0, len = previousKeys.length; i < len; i++) {
@@ -126,7 +141,20 @@ export function reconcile<T extends U, U>(
126141
v = unwrap(value);
127142
return state => {
128143
if (!isWrappable(state) || !isWrappable(v)) return v;
129-
const res = applyState(v, { [$ROOT]: state }, $ROOT, merge, key);
144+
const res = applyState(v, { [$ROOT]: state }, $ROOT, merge, key, null, null);
145+
return res === undefined ? (state as T) : res;
146+
};
147+
}
148+
149+
export function reconcileWithKeys<T extends U, U>(
150+
value: T,
151+
options: ReconcileWithKeysOptions = {}
152+
): (state: U) => T {
153+
const { merge, keys = emptyKeys } = options,
154+
v = unwrap(value);
155+
return state => {
156+
if (!isWrappable(state) || !isWrappable(v)) return v;
157+
const res = applyState(v, { [$ROOT]: state }, $ROOT, merge, keys._key, keys, true);
130158
return res === undefined ? (state as T) : res;
131159
};
132160
}

packages/solid/store/test/modifiers.spec.ts

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
import { createRoot, createSignal, createEffect } from "../../src";
2-
import { createStore, createMutable, reconcile, produce, unwrap, modifyMutable } from "../src";
2+
import {
3+
createStore,
4+
createMutable,
5+
reconcile,
6+
produce,
7+
unwrap,
8+
modifyMutable,
9+
reconcileWithKeys
10+
} from "../src";
311

412
describe("setState with reconcile", () => {
513
test("Reconcile a simple object", () => {
@@ -357,6 +365,30 @@ describe("modifyMutable with reconcile", () => {
357365
});
358366
});
359367

368+
describe("reconcileWithKeys", () => {
369+
test("simple test", () => {
370+
createRoot(() => {
371+
const [target, setStore] = createStore({
372+
c: [
373+
{ idx: 1, name: "1" },
374+
{ idx: 0, name: "0" }
375+
]
376+
});
377+
378+
const ref1 = target.c[1];
379+
380+
const source = {
381+
c: [{ idx: 0, name: "0 modified" }]
382+
};
383+
384+
setStore("c", reconcile(source.c));
385+
386+
expect(target.c[0]).toBe(ref1);
387+
388+
expect(target).toEqual({ c: [{ idx: 0, name: "0 modified" }] });
389+
});
390+
});
391+
});
360392
// type tests
361393

362394
// reconcile

0 commit comments

Comments
 (0)