Skip to content

Commit f84b81f

Browse files
authored
Merge pull request #463 from elite174/feat/latest
Support temporary `latest` field for `createAsync` and `createAsyncStore`
2 parents 098a794 + 6531a76 commit f84b81f

3 files changed

Lines changed: 43 additions & 9 deletions

File tree

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -495,11 +495,19 @@ This is light wrapper over `createResource` that aims to serve as stand-in for a
495495
const user = createAsync((currentValue) => getUser(params.id))
496496
```
497497

498+
It also preserves `latest` field from `createResource`. Note that it will be removed in the future.
499+
500+
```jsx
501+
const user = createAsync((currentValue) => getUser(params.id))
502+
return <h1>{user.latest.name}</h1>;
503+
```
504+
498505
Using `cache` in `createResource` directly won't work properly as the fetcher is not reactive and it won't invalidate properly.
499506

500507
### `createAsyncStore`
501508

502509
Similar to `createAsync` except it uses a deeply reactive store. Perfect for applying fine-grained changes to large model data that updates.
510+
It also supports `latest` field which will be removed in the future.
503511

504512
```jsx
505513
const todos = createAsyncStore(() => getTodos());

src/data/createAsync.ts

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,38 +5,56 @@ import { type Accessor, createResource, sharedConfig, type Setter, untrack } fro
55
import { createStore, reconcile, type ReconcileOptions, unwrap } from "solid-js/store";
66
import { isServer } from "solid-js/web";
77

8+
/**
9+
* As `createAsync` and `createAsyncStore` are wrappers for `createResource`,
10+
* this type allows to support `latest` field for these primitives.
11+
* It will be removed in the future.
12+
*/
13+
export type AccessorWithLatest<T> = {
14+
(): T;
15+
latest: T;
16+
}
17+
818
export function createAsync<T>(
919
fn: (prev: T) => Promise<T>,
1020
options: {
1121
name?: string;
1222
initialValue: T;
1323
deferStream?: boolean;
1424
}
15-
): Accessor<T>;
25+
): AccessorWithLatest<T>;
1626
export function createAsync<T>(
1727
fn: (prev: T | undefined) => Promise<T>,
1828
options?: {
1929
name?: string;
2030
initialValue?: T;
2131
deferStream?: boolean;
2232
}
23-
): Accessor<T | undefined>;
33+
): AccessorWithLatest<T | undefined>;
2434
export function createAsync<T>(
2535
fn: (prev: T | undefined) => Promise<T>,
2636
options?: {
2737
name?: string;
2838
initialValue?: T;
2939
deferStream?: boolean;
3040
}
31-
): Accessor<T | undefined> {
41+
): AccessorWithLatest<T | undefined> {
3242
let resource: () => T;
3343
let prev = () => !resource || (resource as any).state === "unresolved" ? undefined : (resource as any).latest;
3444
[resource] = createResource(
3545
() => subFetch(fn, untrack(prev)),
3646
v => v,
3747
options as any
3848
);
39-
return () => resource();
49+
50+
const resultAccessor: AccessorWithLatest<T> = (() => resource()) as any;
51+
Object.defineProperty(resultAccessor, 'latest', {
52+
get() {
53+
return (resource as any).latest;
54+
}
55+
})
56+
57+
return resultAccessor;
4058
}
4159

4260
export function createAsyncStore<T>(
@@ -47,7 +65,7 @@ export function createAsyncStore<T>(
4765
deferStream?: boolean;
4866
reconcile?: ReconcileOptions;
4967
}
50-
): Accessor<T>;
68+
): AccessorWithLatest<T>;
5169
export function createAsyncStore<T>(
5270
fn: (prev: T | undefined) => Promise<T>,
5371
options?: {
@@ -56,7 +74,7 @@ export function createAsyncStore<T>(
5674
deferStream?: boolean;
5775
reconcile?: ReconcileOptions;
5876
}
59-
): Accessor<T | undefined>;
77+
): AccessorWithLatest<T | undefined>;
6078
export function createAsyncStore<T>(
6179
fn: (prev: T | undefined) => Promise<T>,
6280
options: {
@@ -65,7 +83,7 @@ export function createAsyncStore<T>(
6583
deferStream?: boolean;
6684
reconcile?: ReconcileOptions;
6785
} = {}
68-
): Accessor<T | undefined> {
86+
): AccessorWithLatest<T | undefined> {
6987
let resource: () => T;
7088
let prev = () => !resource || (resource as any).state === "unresolved" ? undefined : unwrap((resource as any).latest);
7189
[resource] = createResource(
@@ -76,7 +94,15 @@ export function createAsyncStore<T>(
7694
storage: (init: T | undefined) => createDeepSignal(init, options.reconcile)
7795
} as any
7896
);
79-
return () => resource();
97+
98+
const resultAccessor: AccessorWithLatest<T> = (() => resource()) as any;
99+
Object.defineProperty(resultAccessor, 'latest', {
100+
get() {
101+
return (resource as any).latest;
102+
}
103+
})
104+
105+
return resultAccessor;
80106
}
81107

82108
function createDeepSignal<T>(value: T | undefined, options?: ReconcileOptions) {

src/data/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export { createAsync, createAsyncStore } from "./createAsync.js";
1+
export { createAsync, createAsyncStore, type AccessorWithLatest } from "./createAsync.js";
22
export { action, useSubmission, useSubmissions, useAction, type Action } from "./action.js";
33
export { cache, revalidate, type CachedFunction } from "./cache.js";
44
export { redirect, reload, json } from "./response.js";

0 commit comments

Comments
 (0)