← スキル一覧に戻る

dojo-state
by dojoengine
Official JavaScript packages for Dojo.
⭐ 37🍴 55📅 2026年1月23日
SKILL.md
name: dojo-state description: | Use when managing game state with Zustand in dojo.js. Triggers: dojo state, zustand dojo, game state, createDojoStore, optimistic update, getEntity, mergeEntities, state management, revert transaction
Dojo.js State Management
When to Use
Use this skill when:
- Setting up the Zustand store for game state
- Accessing entities from the store
- Implementing optimistic updates
- Working with historical entity data
Store Setup
import { createDojoStore } from "@dojoengine/sdk/react";
import type { GameState } from "@dojoengine/state/zustand";
// Create typed store
const useDojoStore = createDojoStore<typeof schema>();
GameState Interface
interface GameState<T> {
entities: Record<string, ParsedEntity<T>>;
historical_entities: Record<string, ParsedEntity<T>[]>;
pendingTransactions: Record<string, PendingTransaction>;
// Entity operations
setEntities: (entities: ParsedEntity<T>[]) => void;
mergeEntities: (entities: ParsedEntity<T>[]) => void;
updateEntity: (entity: Partial<ParsedEntity<T>>) => void;
// Historical operations
setHistoricalEntities: (entities: ParsedEntity<T>[]) => void;
mergeHistoricalEntities: (entities: ParsedEntity<T>[]) => void;
// Optimistic updates
applyOptimisticUpdate: (transactionId: string, updateFn: (draft) => void) => void;
revertOptimisticUpdate: (transactionId: string) => void;
confirmTransaction: (transactionId: string) => void;
// Queries
getEntity: (entityId: string) => ParsedEntity<T> | undefined;
getEntities: (filter?: (entity) => boolean) => ParsedEntity<T>[];
getEntitiesByModel: (namespace: keyof T, model: keyof T[keyof T]) => ParsedEntity<T>[];
getHistoricalEntities: (entityId: string) => ParsedEntity<T>[];
// Subscriptions
subscribeToEntity: (entityId: string, listener: (entity) => void) => () => void;
waitForEntityChange: (entityId: string, predicate: (entity) => boolean, timeout?: number) => Promise<ParsedEntity<T> | undefined>;
// Cleanup
resetStore: () => void;
}
Accessing Store Data
import { useDojoSDK } from "@dojoengine/sdk/react";
function GameComponent() {
const { useDojoStore } = useDojoSDK();
// Get single entity
const player = useDojoStore(state => state.getEntity(entityId));
// Get all entities with filter
const activePlayers = useDojoStore(state =>
state.getEntities(e => e.models?.game?.Player?.isActive)
);
// Get entities by model
const allPlayers = useDojoStore(state =>
state.getEntitiesByModel("game", "Player")
);
}
Optimistic Updates
Optimistic updates show changes immediately while the transaction confirms:
function movePlayer(direction: string) {
const { useDojoStore, provider } = useDojoSDK();
const store = useDojoStore.getState();
const transactionId = `move-${Date.now()}`;
// 1. Apply optimistic update immediately
store.applyOptimisticUpdate(transactionId, (draft) => {
const entity = draft.entities[entityId];
if (entity?.models?.game?.Position) {
entity.models.game.Position.x += direction === "right" ? 1 : -1;
}
});
try {
// 2. Execute the actual transaction
await provider.execute(account, {
contractName: "actions",
entrypoint: "move",
calldata: [direction]
}, "game");
// 3. Confirm on success (removes pending state)
store.confirmTransaction(transactionId);
} catch (error) {
// 4. Revert on failure
store.revertOptimisticUpdate(transactionId);
}
}
Entity Subscriptions
function useEntitySubscription(entityId: string) {
const { useDojoStore } = useDojoSDK();
const store = useDojoStore.getState();
useEffect(() => {
const unsubscribe = store.subscribeToEntity(entityId, (entity) => {
console.log("Entity changed:", entity);
});
return () => unsubscribe();
}, [entityId]);
}
Waiting for Entity Changes
async function waitForMove(entityId: string) {
const { useDojoStore } = useDojoSDK();
const store = useDojoStore.getState();
const entity = await store.waitForEntityChange(
entityId,
(entity) => entity?.models?.game?.Position?.x > 10,
30000 // 30 second timeout
);
if (entity) {
console.log("Player reached position:", entity.models.game.Position);
}
}
Historical Entities
function PlayerTimeline({ entityId }) {
const { useDojoStore } = useDojoSDK();
const history = useDojoStore(state =>
state.getHistoricalEntities(entityId)
);
return (
<ul>
{history.map((snapshot, i) => (
<li key={i}>
Position: ({snapshot.models.game.Position.x}, {snapshot.models.game.Position.y})
</li>
))}
</ul>
);
}
Merging Entities from Subscriptions
const { sdk, useDojoStore } = useDojoSDK();
await sdk.subscribeEntityQuery({
query: query,
callback: ({ data }) => {
if (data) {
// Merge updates into store
useDojoStore.getState().mergeEntities([data]);
}
}
});
Common Pitfalls
- Forgetting to confirm/revert: Always handle both success and error cases for optimistic updates
- Stale closures: Use
useDojoStore.getState()for callbacks to avoid stale state - Over-subscribing: Use selectors to minimize re-renders
- Missing cleanup: Always unsubscribe from entity subscriptions on unmount
スコア
総合スコア
70/100
リポジトリの品質指標に基づく評価
✓SKILL.md
SKILL.mdファイルが含まれている
+20
✓LICENSE
ライセンスが設定されている
+10
○説明文
100文字以上の説明がある
0/10
○人気
GitHub Stars 100以上
0/15
✓最近の活動
1ヶ月以内に更新
+10
✓フォーク
10回以上フォークされている
+5
✓Issue管理
オープンIssueが50未満
+5
✓言語
プログラミング言語が設定されている
+5
✓タグ
1つ以上のタグが設定されている
+5
レビュー
💬
レビュー機能は近日公開予定です
