Skip to content

Commit 6def43b

Browse files
authored
feat: defer directives (#864)
1 parent 7200a1e commit 6def43b

13 files changed

Lines changed: 906 additions & 216 deletions

File tree

.changeset/tender-years-draw.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"@reactive-dot/react": minor
3+
"@reactive-dot/core": minor
4+
"@reactive-dot/vue": minor
5+
---
6+
7+
Introduced the `defer` directive to enable incremental loading for single queries, improving performance and user experience by allowing partial data to be rendered as it becomes available.

apps/docs/react/guides/incremental-loading.md

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,36 @@ sidebar_position: 4
44

55
# Incremental loading
66

7+
## `defer`
8+
9+
The `defer` directive may be specified on a query to imply de-prioritization, that causes the data to be in [`pending`](/api/core#pending) state in the initial response, and delivered as a subsequent response afterward. For React, this can also be used to opt-out of suspending.
10+
11+
:::info
12+
13+
When you pass `{ defer: true }` to the query, the result will now be either:
14+
15+
- A resolved value (the response you expect), or
16+
- A special [`pending`](/api/core#pending) symbol from `@reactive-dot/core`, indicating that the data hasn’t arrived yet.
17+
18+
:::
19+
20+
```tsx
21+
import { pending } from "@reactive-dot/core";
22+
import { useLazyLoadQuery } from "@reactive-dot/react";
23+
24+
export function Tvl() {
25+
const tvl = useLazyLoadQuery((query) =>
26+
query.storage("NominationPools", "TotalValueLocked", [], { defer: true }),
27+
);
28+
29+
if (tvl === pending) {
30+
return <progress />;
31+
}
32+
33+
return <p>Total value locked: {tvl}</p>;
34+
}
35+
```
36+
737
## `stream`
838

939
For multi-entry queries like `storages`, `runtimeApis`, etc., the `stream` directive allows the client to receive partial results as they become available, before the entire response is ready.
@@ -35,7 +65,7 @@ This works well for a small number of accounts, where results load quickly. But
3565
When you pass `{ stream: true }` to the query, each item in the result array will now be either:
3666

3767
- A resolved value (the response you expect), or
38-
- A special `pending` symbol from `@reactive-dot/core`, indicating that the data for that item hasn’t arrived yet.
68+
- A special [`pending`](/api/core#pending) symbol from `@reactive-dot/core`, indicating that the data for that item hasn’t arrived yet.
3969

4070
:::
4171

apps/docs/vue/guides/incremental-loading.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,34 @@ sidebar_position: 3
44

55
# Incremental loading
66

7+
## `defer`
8+
9+
The `defer` directive may be specified on a query to imply de-prioritization, that causes the data to be in [`pending`](/api/core#pending) state in the initial response, and delivered as a subsequent response afterward.
10+
11+
:::info
12+
13+
When you pass `{ defer: true }` to the query, the result will now be either:
14+
15+
- A resolved value (the response you expect), or
16+
- A special [`pending`](/api/core#pending) symbol from `@reactive-dot/core`, indicating that the data hasn’t arrived yet.
17+
18+
:::
19+
20+
```vue
21+
<script setup lang="ts">
22+
import { useLazyLoadQuery } from "@reactive-dot/vue";
23+
24+
const { data: tvl } = await useLazyLoadQuery((query) =>
25+
query.storage("NominationPools", "TotalValueLocked", [], { defer: true }),
26+
);
27+
</script>
28+
29+
<template>
30+
<progress v-if="tvl === pending" />
31+
<p v-else>Total staked: {{ totalStaked }}</p>
32+
</template>
33+
```
34+
735
## `stream`
836

937
For multi-entry queries like `storages`, `runtimeApis`, etc., the `stream` directive allows the client to receive partial results as they become available, before the entire response is ready.

packages/core/src/actions/query.test.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ describe("preflight", () => {
5959
api: "foo",
6060
args: [],
6161
at: undefined,
62+
directives: {
63+
defer: undefined,
64+
},
6265
} as SimpleQueryInstruction;
6366

6467
expect(preflight(instruction)).toBe("promise");
@@ -71,6 +74,9 @@ describe("preflight", () => {
7174
storage: "foo",
7275
args: [],
7376
at: undefined,
77+
directives: {
78+
defer: undefined,
79+
},
7480
} as SimpleQueryInstruction;
7581

7682
expect(preflight(instruction)).toBe("observable");
@@ -83,6 +89,9 @@ describe("preflight", () => {
8389
storage: "foo",
8490
args: [],
8591
at: undefined,
92+
directives: {
93+
defer: undefined,
94+
},
8695
} as SimpleQueryInstruction;
8796

8897
expect(preflight(instruction)).toBe("observable");
@@ -95,6 +104,9 @@ describe("preflight", () => {
95104
storage: "foo",
96105
args: [1],
97106
at: "0x1234",
107+
directives: {
108+
defer: undefined,
109+
},
98110
} as SimpleQueryInstruction;
99111

100112
expect(preflight(instruction)).toBe("promise");
@@ -136,6 +148,9 @@ it('should handle "read-storage" instruction with at starting with "0x" (using g
136148
storage: "foo",
137149
args: [3],
138150
at: "0xabc",
151+
directives: {
152+
defer: undefined,
153+
},
139154
} as SimpleQueryInstruction;
140155

141156
const result = await query(fakeApi, instruction);
@@ -170,6 +185,9 @@ it('should handle "read-storage-entries" instruction with at starting with "0x"
170185
storage: "foo",
171186
args: [3],
172187
at: "0xabc",
188+
directives: {
189+
defer: undefined,
190+
},
173191
} as SimpleQueryInstruction;
174192

175193
const result = await query(fakeApi, instruction);

packages/core/src/contract/ink/query-builder.test.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ describe("rootStorage", () => {
2121
[
2222
{
2323
"at": undefined,
24+
"directives": {
25+
"defer": undefined,
26+
},
2427
"instruction": "read-storage",
2528
"key": undefined,
2629
"path": "",
@@ -35,6 +38,9 @@ describe("rootStorage", () => {
3538
[
3639
{
3740
"at": "finalized",
41+
"directives": {
42+
"defer": undefined,
43+
},
3844
"instruction": "read-storage",
3945
"key": undefined,
4046
"path": "",
@@ -51,6 +57,9 @@ describe("storage", () => {
5157
[
5258
{
5359
"at": undefined,
60+
"directives": {
61+
"defer": undefined,
62+
},
5463
"instruction": "read-storage",
5564
"key": undefined,
5665
"path": "test-path",
@@ -65,6 +74,9 @@ describe("storage", () => {
6574
[
6675
{
6776
"at": undefined,
77+
"directives": {
78+
"defer": undefined,
79+
},
6880
"instruction": "read-storage",
6981
"key": "key-value",
7082
"path": "test-path",
@@ -81,6 +93,9 @@ describe("storage", () => {
8193
[
8294
{
8395
"at": "finalized",
96+
"directives": {
97+
"defer": undefined,
98+
},
8499
"instruction": "read-storage",
85100
"key": "key-value",
86101
"path": "test-path",
@@ -98,6 +113,7 @@ describe("storages", () => {
98113
{
99114
"at": undefined,
100115
"directives": {
116+
"defer": undefined,
101117
"stream": undefined,
102118
},
103119
"instruction": "read-storage",
@@ -121,6 +137,7 @@ describe("storages", () => {
121137
{
122138
"at": "finalized",
123139
"directives": {
140+
"defer": undefined,
124141
"stream": undefined,
125142
},
126143
"instruction": "read-storage",
@@ -144,6 +161,9 @@ describe("message", () => {
144161
{
145162
"at": undefined,
146163
"body": undefined,
164+
"directives": {
165+
"defer": undefined,
166+
},
147167
"instruction": "send-message",
148168
"name": "test-message",
149169
"origin": undefined,
@@ -161,6 +181,9 @@ describe("message", () => {
161181
"body": {
162182
"foo": "bar",
163183
},
184+
"directives": {
185+
"defer": undefined,
186+
},
164187
"instruction": "send-message",
165188
"name": "test-message",
166189
"origin": undefined,
@@ -182,6 +205,9 @@ describe("message", () => {
182205
"body": {
183206
"foo": "bar",
184207
},
208+
"directives": {
209+
"defer": undefined,
210+
},
185211
"instruction": "send-message",
186212
"name": "test-message",
187213
"origin": undefined,
@@ -210,6 +236,7 @@ describe("messages", () => {
210236
},
211237
],
212238
"directives": {
239+
"defer": undefined,
213240
"stream": undefined,
214241
},
215242
"instruction": "send-message",
@@ -240,6 +267,7 @@ describe("messages", () => {
240267
},
241268
],
242269
"directives": {
270+
"defer": undefined,
243271
"stream": undefined,
244272
},
245273
"instruction": "send-message",
@@ -265,6 +293,9 @@ describe("chaining", () => {
265293
expect(query.instructions[0]).toMatchInlineSnapshot(`
266294
{
267295
"at": undefined,
296+
"directives": {
297+
"defer": undefined,
298+
},
268299
"instruction": "read-storage",
269300
"key": "key1",
270301
"path": "path1",
@@ -273,6 +304,9 @@ describe("chaining", () => {
273304
expect(query.instructions[4]).toMatchInlineSnapshot(`
274305
{
275306
"at": "finalized",
307+
"directives": {
308+
"defer": undefined,
309+
},
276310
"instruction": "read-storage",
277311
"key": undefined,
278312
"path": "",

0 commit comments

Comments
 (0)