From afce5fa7c112ea2462d5eac6fdb199ef0f3fc46b Mon Sep 17 00:00:00 2001 From: Victor Oliva Date: Tue, 15 Nov 2022 10:55:57 +0100 Subject: [PATCH] fix: routeState routes not updating if the key stays the same (#286) --- .../context-state/src/route-state.test.ts | 48 +++++++++++++++++++ packages/context-state/src/route-state.ts | 19 +++++--- 2 files changed, 61 insertions(+), 6 deletions(-) diff --git a/packages/context-state/src/route-state.test.ts b/packages/context-state/src/route-state.test.ts index edb0862..8a333ed 100644 --- a/packages/context-state/src/route-state.test.ts +++ b/packages/context-state/src/route-state.test.ts @@ -186,5 +186,53 @@ describe("routeState", () => { expect(a.getValue()).toEqual("a mapped a") }) + + it("emits new values when the route stays the same", () => { + const root = createRoot() + const parentSource = new Subject<"a" | "b">() + const parent = substate(root, () => parentSource) + const [, { a }] = routeState( + parent, + { + a: (v) => "a mapped " + v, + }, + () => "a", + ) + + root.run() + + parentSource.next("a") + parentSource.next("b") + + expect(a.getValue()).toEqual("a mapped b") + }) + + it("doesn't update if the value returns the same as before", () => { + const root = createRoot() + const parentSource = new Subject<"a" | "b">() + const parent = substate(root, () => parentSource) + const [, { a }] = routeState( + parent, + { + a: (v) => "a mapped " + v, + }, + () => "a", + ) + + root.run() + + const childSpy = jest.fn() + substate(a, () => { + childSpy() + return of("") + }) + + parentSource.next("a") + expect(childSpy).toHaveBeenCalledTimes(1) + parentSource.next("a") + expect(childSpy).toHaveBeenCalledTimes(1) + parentSource.next("b") + expect(childSpy).toHaveBeenCalledTimes(2) + }) }) }) diff --git a/packages/context-state/src/route-state.ts b/packages/context-state/src/route-state.ts index 33830ea..d39475f 100644 --- a/packages/context-state/src/route-state.ts +++ b/packages/context-state/src/route-state.ts @@ -37,11 +37,15 @@ export const routeState = < ): [StateNode, OT] => { const internalParent = getInternals(parent) const keys = new Set(Object.keys(routes)) - const keyState = substate(parent, (ctx) => { - const key = selector(ctx(parent), ctx) - if (!keys.has(key)) throw new InvalidRouteError(key, [...keys]) - return of(key) - }) + const keyState = substate( + parent, + (ctx) => { + const key = selector(ctx(parent), ctx) + if (!keys.has(key)) throw new InvalidRouteError(key, [...keys]) + return of(key) + }, + () => false, + ) const routedState = mapRecord(routes, (mapper) => { const result = detachedNode(internalParent.keysOrder, (ctx) => { @@ -72,5 +76,8 @@ export const routeState = < getInternals(keyState).childRunners.push(run) - return [keyState, mapRecord(routedState, (x) => x.public) as OT] + return [ + substate(keyState, (ctx) => of(ctx(keyState))), + mapRecord(routedState, (x) => x.public) as OT, + ] }