From e0887b6de8e3cc283cc81ac93dffda323b7c6882 Mon Sep 17 00:00:00 2001 From: Brenley Dueck Date: Sat, 23 May 2026 21:24:26 -0500 Subject: [PATCH 1/2] fix: clear projection initial pending state --- packages/solid-signals/src/core/async.ts | 6 ++- .../tests/createLoadingBoundary.test.ts | 38 +++++++++++++++++++ 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/packages/solid-signals/src/core/async.ts b/packages/solid-signals/src/core/async.ts index 54770abda..b2f0c9da2 100644 --- a/packages/solid-signals/src/core/async.ts +++ b/packages/solid-signals/src/core/async.ts @@ -197,8 +197,10 @@ export function handleAsync( clearStatus(el); const lane = resolveLane(el as any); if (lane) lane._pendingAsync.delete(el); - if (setter) setter(value); - else if (el._overrideValue !== undefined) { + if (setter) { + setter(value); + if (wasUninitialized) clearStatus(el, true); + } else if (el._overrideValue !== undefined) { if (el._overrideValue !== undefined && el._overrideValue !== NOT_PENDING) el._pendingValue = value; else { diff --git a/packages/solid-signals/tests/createLoadingBoundary.test.ts b/packages/solid-signals/tests/createLoadingBoundary.test.ts index aec48622d..bf50821e1 100644 --- a/packages/solid-signals/tests/createLoadingBoundary.test.ts +++ b/packages/solid-signals/tests/createLoadingBoundary.test.ts @@ -93,6 +93,44 @@ describe("createLoadingBoundary", () => { expect(result).toBe(0); // Should show 0, not "loading" }); + it("reports pending on first refresh after an async projection resolves", async () => { + let result: any; + let projection!: { value: number }; + let current = deferred<{ value: number }>(); + + createRoot(() => { + projection = createProjection(async () => current.promise, {} as { value: number }); + + const boundary = createLoadingBoundary( + () => [projection.value, isPending(() => projection.value)], + () => "loading" + ); + + createRenderEffect( + () => (result = boundary()), + () => {} + ); + }); + + flush(); + expect(result).toBe("loading"); + + current.resolve({ value: 1 }); + await new Promise(resolve => setTimeout(resolve, 0)); + flush(); + expect(result).toEqual([1, false]); + + current = deferred<{ value: number }>(); + refresh(projection); + flush(); + expect(result).toEqual([1, true]); + + current.resolve({ value: 2 }); + await new Promise(resolve => setTimeout(resolve, 0)); + flush(); + expect(result).toEqual([2, false]); + }); + it("clears loading for multiple effects in same boundary", async () => { let result1: any, result2: any; From 74fdc8332aa49d4dd7ddec4aa82cc064e069926e Mon Sep 17 00:00:00 2001 From: Ryan Carniato Date: Mon, 25 May 2026 22:33:24 -0700 Subject: [PATCH 2/2] fix: add projection pending changeset Co-authored-by: Cursor --- .changeset/fix-projection-refresh-pending.md | 5 +++++ packages/solid-signals/tests/createLoadingBoundary.test.ts | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 .changeset/fix-projection-refresh-pending.md diff --git a/.changeset/fix-projection-refresh-pending.md b/.changeset/fix-projection-refresh-pending.md new file mode 100644 index 000000000..c5e649d48 --- /dev/null +++ b/.changeset/fix-projection-refresh-pending.md @@ -0,0 +1,5 @@ +--- +"@solidjs/signals": patch +--- + +Fix projection pending state on first refresh after initial async resolution. diff --git a/packages/solid-signals/tests/createLoadingBoundary.test.ts b/packages/solid-signals/tests/createLoadingBoundary.test.ts index bf50821e1..8740f86b7 100644 --- a/packages/solid-signals/tests/createLoadingBoundary.test.ts +++ b/packages/solid-signals/tests/createLoadingBoundary.test.ts @@ -11,6 +11,7 @@ import { isPending, latest, NotReadyError, + type Refreshable, type SourceAccessor, refresh, untrack @@ -95,7 +96,7 @@ describe("createLoadingBoundary", () => { it("reports pending on first refresh after an async projection resolves", async () => { let result: any; - let projection!: { value: number }; + let projection!: Refreshable<{ value: number }>; let current = deferred<{ value: number }>(); createRoot(() => {