Skip to content

Commit 1427acb

Browse files
committed
feat: compare state equality
1 parent 026fdca commit 1427acb

File tree

3 files changed

+40
-12
lines changed

3 files changed

+40
-12
lines changed

src/routers/createRouter.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Signal, createSignal, onCleanup } from "solid-js";
22
import type { LocationChange, RouterContext, RouterUtils } from "../types.ts";
33
import { createRouterComponent } from "./components.jsx";
4+
import { equalObjects } from "../utils.js";
45

56
function intercept<T>(
67
[value, setValue]: [() => T, (v: T) => void],
@@ -32,7 +33,9 @@ export function createRouter(config: {
3233
let ignore = false;
3334
const wrap = (value: string | LocationChange) => (typeof value === "string" ? { value } : value);
3435
const signal = intercept<LocationChange>(
35-
createSignal(wrap(config.get()), { equals: false }),
36+
createSignal(wrap(config.get()), {
37+
equals: (a, b) => a.value === b.value && equalObjects(a.state, b.state)
38+
}),
3639
undefined,
3740
next => {
3841
!ignore && config.set(next);

src/routing.ts

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ import {
4444
joinPaths,
4545
scoreRoute,
4646
mergeSearchString,
47-
expandOptionals
47+
expandOptionals,
48+
equalObjects
4849
} from "./utils.js";
4950

5051
const MAX_REDIRECTS = 100;
@@ -327,26 +328,19 @@ export function createRouterContext(
327328
};
328329

329330
createRenderEffect(() => {
330-
const { value, state } = source();
331+
const { value, state: nextState } = source();
331332
// Untrack this whole block so `start` doesn't cause Solid's Listener to be preserved
332333
untrack(() => {
333-
if (value !== reference()) {
334+
if (value !== reference() || !equalObjects(nextState, state())) {
334335
start(() => {
335336
intent = "native";
336337
setReference(value);
337-
setState(state);
338+
setState(nextState);
338339
resetErrorBoundaries();
339340
submissions[1]([]);
340341
}).then(() => {
341342
intent = undefined;
342343
});
343-
} else {
344-
start(() => {
345-
intent = "native";
346-
setState(state);
347-
}).then(() => {
348-
intent = undefined;
349-
});
350344
}
351345
});
352346
});

src/utils.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,3 +186,34 @@ export function expandOptionals(pattern: string): string[] {
186186
[]
187187
);
188188
}
189+
190+
// Modified from fast-deep-equal for objects only (MIT)
191+
// https://github.com/epoberezkin/fast-deep-equal
192+
export function equalObjects(a: any, b: any) {
193+
if (a === b) return true;
194+
195+
if (a && b && typeof a == "object" && typeof b == "object") {
196+
if (a.constructor !== b.constructor) return false;
197+
if (a.valueOf !== Object.prototype.valueOf) return a.valueOf() === b.valueOf();
198+
if (a.toString !== Object.prototype.toString) return a.toString() === b.toString();
199+
200+
var length, i, keys;
201+
keys = Object.keys(a);
202+
length = keys.length;
203+
204+
if (length !== Object.keys(b).length) return false;
205+
206+
for (i = length; i-- !== 0; ) {
207+
if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false;
208+
}
209+
210+
for (i = length; i-- !== 0; ) {
211+
var key = keys[i];
212+
if (!equalObjects(a[key], b[key])) return false;
213+
}
214+
215+
return true;
216+
}
217+
218+
return false;
219+
}

0 commit comments

Comments
 (0)