Skip to content

Commit 2fe9c64

Browse files
feat: optimistic example
1 parent 94f15c6 commit 2fe9c64

File tree

4 files changed

+148
-15
lines changed

4 files changed

+148
-15
lines changed

examples/example-vite-react-sdk/src/App.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { addAddressPadding } from "starknet";
66
import { Models, Schema } from "./bindings.ts";
77
import { useDojo } from "./useDojo.tsx";
88
import useModel from "./useModel.tsx";
9+
import { useSystemCalls } from "./useSystemCalls.ts";
910

1011
export const useDojoStore = createDojoStore<Schema>();
1112

@@ -17,6 +18,8 @@ function App({ db }: { db: SDK<Schema> }) {
1718
const state = useDojoStore((state) => state);
1819
const entities = useDojoStore((state) => state.entities);
1920

21+
const { spawn } = useSystemCalls();
22+
2023
const entityId = useMemo(
2124
() => getEntityIdFromKeys([BigInt(account?.account.address)]),
2225
[account?.account.address]
@@ -161,11 +164,7 @@ function App({ db }: { db: SDK<Schema> }) {
161164
<div className="col-start-2">
162165
<button
163166
className="h-12 w-12 bg-gray-600 rounded-full shadow-md active:shadow-inner active:bg-gray-500 focus:outline-none text-2xl font-bold text-gray-200"
164-
onClick={async () =>
165-
await client.actions.spawn({
166-
account: account.account,
167-
})
168-
}
167+
onClick={async () => await spawn()}
169168
>
170169
+
171170
</button>
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import { getEntityIdFromKeys } from "@dojoengine/utils";
2+
import { useDojoStore } from "./App";
3+
import { useDojo } from "./useDojo";
4+
import { v4 as uuidv4 } from "uuid";
5+
6+
export const useSystemCalls = () => {
7+
const state = useDojoStore((state) => state);
8+
9+
const {
10+
setup: { client },
11+
account: { account },
12+
} = useDojo();
13+
14+
const generateEntityId = () => {
15+
return getEntityIdFromKeys([BigInt(account?.address)]);
16+
};
17+
18+
const spawn = async () => {
19+
// Generate a unique entity ID
20+
const entityId = generateEntityId();
21+
22+
// Generate a unique transaction ID
23+
const transactionId = uuidv4();
24+
25+
// The value to update the Moves model with
26+
const remainingMoves = 100;
27+
28+
// Apply an optimistic update to the state
29+
// this uses immer drafts to update the state
30+
state.applyOptimisticUpdate(
31+
transactionId,
32+
(draft) =>
33+
(draft.entities[entityId].models.dojo_starter.Moves!.remaining =
34+
remainingMoves)
35+
);
36+
37+
try {
38+
// Execute the spawn action from the client
39+
await client.actions.spawn({ account });
40+
41+
// Wait for the entity to be updated with the new state
42+
await state.waitForEntityChange(entityId, (entity) => {
43+
return (
44+
entity?.models?.dojo_starter?.Moves?.remaining ===
45+
remainingMoves
46+
);
47+
});
48+
} catch (error) {
49+
// Revert the optimistic update if an error occurs
50+
state.revertOptimisticUpdate(transactionId);
51+
console.error("Error executing spawn:", error);
52+
throw error;
53+
} finally {
54+
// Confirm the transaction if successful
55+
state.confirmTransaction(transactionId);
56+
}
57+
};
58+
59+
return {
60+
spawn,
61+
};
62+
};

packages/sdk/readme.md

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,79 @@ const subscription = await sdk.subscribeEntityQuery(
344344
345345
## Optimistic Client Rendering
346346
347-
<!-- TODO -->
347+
We use [immer](https://immerjs.github.io/immer/) for efficient optimistic rendering. This allows instant client-side entity state updates while awaiting blockchain confirmation.
348+
349+
The process:
350+
351+
1. Update entity state optimistically.
352+
2. Wait for condition (e.g., a specific state change).
353+
3. Resolve update, providing immediate user feedback.
354+
355+
This ensures a responsive user experience while maintaining blockchain data integrity.
356+
357+
See our [example project](../../examples/example-vite-react-sdk/src/useSystemCalls.ts) for a real-world implementation.
358+
359+
Note: You will need to have a subscription running in order for the update to resolve.
360+
361+
```typescript
362+
export const useSystemCalls = () => {
363+
const state = useDojoStore((state) => state);
364+
365+
const {
366+
setup: { client },
367+
account: { account },
368+
} = useDojo();
369+
370+
const generateEntityId = () => {
371+
return getEntityIdFromKeys([BigInt(account?.address)]);
372+
};
373+
374+
const spawn = async () => {
375+
// Generate a unique entity ID
376+
const entityId = generateEntityId();
377+
378+
// Generate a unique transaction ID
379+
const transactionId = uuidv4();
380+
381+
// The value to update
382+
const remainingMoves = 100;
383+
384+
// Apply an optimistic update to the state
385+
// this uses immer drafts to update the state
386+
state.applyOptimisticUpdate(
387+
transactionId,
388+
(draft) =>
389+
(draft.entities[entityId].models.dojo_starter.Moves!.remaining =
390+
remainingMoves)
391+
);
392+
393+
try {
394+
// Execute the spawn action
395+
await client.actions.spawn({ account });
396+
397+
// Wait for the entity to be updated with the new state
398+
await state.waitForEntityChange(entityId, (entity) => {
399+
return (
400+
entity?.models?.dojo_starter?.Moves?.remaining ===
401+
remainingMoves
402+
);
403+
});
404+
} catch (error) {
405+
// Revert the optimistic update if an error occurs
406+
state.revertOptimisticUpdate(transactionId);
407+
console.error("Error executing spawn:", error);
408+
throw error;
409+
} finally {
410+
// Confirm the transaction if successful
411+
state.confirmTransaction(transactionId);
412+
}
413+
};
414+
415+
return {
416+
spawn,
417+
};
418+
};
419+
```
348420
349421
# Advanced Usage
350422

readme.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ If you are not familiar with Dojo, then you should read the [book](https://book.
2020

2121
- [Quick start in 5 minutes](#quick-start-in-5-minutes)
2222
- [Dojo SDK](#dojo-sdk)
23-
- [Examples](#examples)
23+
- [Examples](#all-examples)
2424
- [All Packages](#all-packages)
2525

2626
## Quick start in 5 minutes
@@ -70,7 +70,7 @@ pnpm i @dojoengine/sdk
7070
```
7171
7272
> Basic example: [example-vite-react-sdk](./examples/example-vite-react-sdk/)
73-
> More complex: [example-vite-react-sdk](./examples/example-vite-kitchen-sink/)
73+
> More complex: [example-vite-kitchen-sink](./examples/example-vite-kitchen-sink/)
7474
7575
```js
7676
// Create client with your parameters
@@ -153,13 +153,13 @@ Spin any of these examples locally
153153
npx @dojoengine/create-dojo start
154154
```
155155

156-
- [example-vite-react-sdk](./examples/example-vite-react-sdk/): A React application using Vite and the Dojo SDK
157-
- [example-vite-react-phaser-recs](./examples/example-vite-react-phaser-recs/): A React application using Vite and the Dojo SDK
158-
- [example-vite-react-pwa-recs](./examples/example-vite-react-pwa-recs/): A React application using Vite and the Dojo SDK
159-
- [example-vite-react-threejs-recs](./examples/example-vite-react-threejs-recs/): A React application using Vite and the Dojo SDK
160-
- [example-vue-app-recs](./examples/example-vue-app-recs/): A React application using Vite and the Dojo SDK
161-
- [example-vite-kitchen-sink](./examples/example-vite-kitchen-sink/): A React application using Vite and the Dojo SDK
162-
- [example-nodejs-bot](./examples/example-nodejs-bot/): A React application using Vite and the Dojo SDK
156+
- [example-vite-react-sdk](./examples/example-vite-react-sdk/)
157+
- [example-vite-react-phaser-recs](./examples/example-vite-react-phaser-recs/)
158+
- [example-vite-react-pwa-recs](./examples/example-vite-react-pwa-recs/)
159+
- [example-vite-react-threejs-recs](./examples/example-vite-react-threejs-recs/)
160+
- [example-vue-app-recs](./examples/example-vue-app-recs/)
161+
- [example-vite-kitchen-sink](./examples/example-vite-kitchen-sink/)
162+
- [example-nodejs-bot](./examples/example-nodejs-bot/)
163163

164164
## Contributing to dojo.js
165165

0 commit comments

Comments
 (0)