Skip to content

Commit 127fc0d

Browse files
alxhubpkozlowski-opensource
authored andcommitted
fix(core): fix resource()'s previous.state (#59708)
When a resource first starts up, even if it transitions immediately to `Loading` it should report a `previous.state` of `Idle`. It was reporting `Loading` as the previous state in such a case because of an oversight in the migration to `linkedSignal` which this commit addresses. PR Close #59708
1 parent b7dd048 commit 127fc0d

File tree

2 files changed

+26
-7
lines changed

2 files changed

+26
-7
lines changed

packages/core/src/resource/resource.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ class ResourceImpl<T, R> extends BaseWritableResource<T> implements ResourceRef<
269269
private async loadEffect(): Promise<void> {
270270
// Capture the previous status before any state transitions. Note that this is `untracked` since
271271
// we do not want the effect to depend on the state of the resource, only on the request.
272-
const {status: previousStatus} = untracked(this.state);
272+
const {status: currentStatus, previousStatus} = untracked(this.state);
273273

274274
const {request, reload: reloadCounter} = this.extendedRequest();
275275
// Subscribe side-effectfully to `reloadCounter`, although we don't actually care about its
@@ -280,8 +280,8 @@ class ResourceImpl<T, R> extends BaseWritableResource<T> implements ResourceRef<
280280
// Nothing to load (and we should already be in a non-loading state).
281281
return;
282282
} else if (
283-
previousStatus !== ResourceStatus.Loading &&
284-
previousStatus !== ResourceStatus.Reloading
283+
currentStatus !== ResourceStatus.Loading &&
284+
currentStatus !== ResourceStatus.Reloading
285285
) {
286286
// We might've transitioned into a loading state, but has since been overwritten (likely via
287287
// `.set`).
@@ -310,15 +310,15 @@ class ResourceImpl<T, R> extends BaseWritableResource<T> implements ResourceRef<
310310
// The actual loading is run through `untracked` - only the request side of `resource` is
311311
// reactive. This avoids any confusion with signals tracking or not tracking depending on
312312
// which side of the `await` they are.
313-
const stream = await untracked(() =>
314-
this.loaderFn({
313+
const stream = await untracked(() => {
314+
return this.loaderFn({
315315
request: request as Exclude<R, undefined>,
316316
abortSignal,
317317
previous: {
318318
status: previousStatus,
319319
},
320-
}),
321-
);
320+
});
321+
});
322322

323323
if (abortSignal.aborted) {
324324
return;

packages/core/test/resource/resource_spec.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,25 @@ describe('resource', () => {
107107
expect(echoResource.error()).toBe(undefined);
108108
});
109109

110+
it('should report idle status as the previous status on first run', async () => {
111+
let prevStatus: ResourceStatus | undefined;
112+
resource({
113+
loader: async ({previous}) => {
114+
// Ensure the loader only runs once.
115+
expect(prevStatus).toBeUndefined();
116+
117+
prevStatus = previous.status;
118+
return true;
119+
},
120+
injector: TestBed.inject(Injector),
121+
});
122+
123+
TestBed.flushEffects();
124+
await flushMicrotasks();
125+
126+
expect(prevStatus).toBe(ResourceStatus.Idle);
127+
});
128+
110129
it('should expose errors thrown during resource loading', async () => {
111130
const backend = new MockEchoBackend();
112131
const requestParam = {};

0 commit comments

Comments
 (0)