Skip to content
dojo-react logo

Dojo.js React Patterns

dojo-react

Use for React integration patterns and best practices in dojo.js. Triggers: dojo react, react hooks, effect atoms, Result.match, infinite scroll dojo, DojoSdkProvider, useDojoSDK, react patterns

dojoengine/dojo.js0installs38stars

SKILL.md

Full skill instructions

Dojo.js React Patterns

When to Use

Use this skill when:

  • Setting up React provider hierarchy
  • Using Effect atoms for complex async state
  • Implementing infinite scroll
  • Handling loading/​error states

Provider Hierarchy

Recommended order:

import { StarknetConfig } from "@starknet-react/​core";
import { DojoSdkProvider } from "@dojoengine/​sdk/​react";

function Providers({ children }) {
    return (
        <StarknetConfig connectors={connectors}>
            <DojoSdkProvider
                dojoConfig={dojoConfig}
                sdk={sdk}
                clientFn={createClient}
            >
                {children}
            </​DojoSdkProvider>
        </​StarknetConfig>
    );
}

useDojoSDK Hook

import { useDojoSDK } from "@dojoengine/​sdk/​react";

function GameComponent() {
    const {
        sdk,          // SDK instance
        config,       // DojoConfig
        client,       // Client from clientFn
        provider,     // DojoProvider
        useDojoStore  // Zustand store hook
    } = useDojoSDK();
}

Effect Atoms (Recommended)

Effect atoms provide robust async state management:

Entity Query Atom

import { createEntityQueryAtom } from "@dojoengine/​react/​effect";
import { Result } from "@dojoengine/​react/​effect";

const playersAtom = createEntityQueryAtom(
    runtime,
    new ToriiQueryBuilder().addEntityModel("game-Player").withLimit(100)
);

function PlayerList() {
    const players = useAtomValue(playersAtom);

    return Result.match(players, {
        onSuccess: ({ value }) => (
            <ul>
                {value.items.map(p => <li key={p.entityId}>{p.models.game.Player.name}</​li>)}
            </​ul>
        ),
        onFailure: (error) => <div>Error: {error.message}</​div>,
        onInitial: () => <div>Loading...</​div>
    });
}

Entity Updates Atom (Real-time)

import { createEntityUpdatesAtom } from "@dojoengine/​react/​effect";

const updatesAtom = createEntityUpdatesAtom(
    runtime,
    KeysClause(["game-Player"], [], "VariableLen").build()
);

Combined Query + Updates

import { createEntityQueryWithUpdatesAtom } from "@dojoengine/​react/​effect";

const livePlayersAtom = createEntityQueryWithUpdatesAtom(
    runtime,
    query,
    clause
);

Infinite Scroll

import { createEntitiesInfiniteScrollAtom } from "@dojoengine/​react/​effect";

const infinitePlayersAtom = createEntitiesInfiniteScrollAtom(
    runtime,
    new ToriiQueryBuilder().addEntityModel("game-Player"),
    20 // page size
);

function InfinitePlayerList() {
    const [state, loadMore] = useAtom(infinitePlayersAtom);

    return Result.match(state, {
        onSuccess: ({ value }) => (
            <>
                <ul>
                    {value.items.map(p => (
                        <li key={p.entityId}>{p.models.game.Player.name}</​li>
                    ))}
                </​ul>
                {value.hasMore && (
                    <button onClick={loadMore}>Load More</​button>
                )}
            </>
        ),
        onFailure: (error) => <div>Error: {error.message}</​div>,
        onInitial: () => <div>Loading...</​div>
    });
}

Token Balance Atoms

import {
    createTokenBalanceQueryAtom,
    createTokenBalanceUpdatesAtom
} from "@dojoengine/​react/​effect";

// One-time query
const balanceAtom = createTokenBalanceQueryAtom(runtime, {
    contractAddresses: ["0x..."],
    accountAddresses: [playerAddress]
});

// Polling updates
const liveBalanceAtom = createTokenBalanceUpdatesAtom(
    runtime,
    { contractAddresses: ["0x..."], accountAddresses: [playerAddress] },
    5000 // poll every 5 seconds
);

Data Formatters

Transform data before rendering:

const formatters = {
    models: {
        "game-Player": (player) => ({
            ...player,
            displayName: player.name || "Anonymous",
            displayScore: `${player.score.toLocaleString()} pts`
        })
    },
    fields: {
        "game-Player.score": (score) => Math.floor(score / 100)
    }
};

const playersAtom = createEntityQueryAtom(runtime, query, formatters);

Custom Subscription Hooks

import { createSubscriptionHook } from "@dojoengine/​sdk/​react";

const usePlayerSubscription = createSubscriptionHook({
    subscribeMethod: (sdk, params) => sdk.subscribeEntityQuery(params),
    processInitialData: (data) => data.items,
    processUpdateData: (update) => update
});

function PlayerTracker({ entityId }) {
    const { data, error, isLoading } = usePlayerSubscription({
        query: new ToriiQueryBuilder()
            .withClause(KeysClause(["game-Player"], [entityId]).build())
    });
}

Zustand Selectors

Optimize re-renders with selectors:

function PlayerScore({ entityId }) {
    const { useDojoStore } = useDojoSDK();

    // Only re-render when score changes
    const score = useDojoStore(
        state => state.entities[entityId]?.models?.game?.Player?.score,
        (a, b) => a === b // equality function
    );

    return <span>{score}</​span>;
}

useEntityId Hook

import { useEntityId } from "@dojoengine/​sdk/​react";

function PlayerCard({ address, gameId }) {
    // Memoized entity ID computation
    const entityId = useEntityId(address, gameId);
    const player = useModel(entityId, "game-Player");
}

Error Boundaries

import { ErrorBoundary } from "react-error-boundary";

function GameErrorFallback({ error, resetErrorBoundary }) {
    return (
        <div>
            <p>Something went wrong: {error.message}</​p>
            <button onClick={resetErrorBoundary}>Retry</​button>
        </​div>
    );
}

function App() {
    return (
        <ErrorBoundary FallbackComponent={GameErrorFallback}>
            <Game />
        </​ErrorBoundary>
    );
}

Common Pitfalls

  1. Missing provider: Ensure DojoSdkProvider wraps all Dojo-using components
  2. Effect runtime: Create runtime once at app startup, not in components
  3. Selector stability: Use stable selector functions to prevent re-renders
  4. Cleanup: Effect atoms handle cleanup, but manual subscriptions need cleanup
  5. Result.match: Always handle all three cases (success, failure, initial)

More skills from dojoengine

dojo-system logo
dojoengine/book

dojo-system

Create Dojo systems that implement game logic, modify model state, and handle player actions. Use when implementing game mechanics, player commands, or automated logic.

53 0
View
m04-zero-cost logo
dojoengine/torii-core

m04-zero-cost

CRITICAL: Use for generics, traits, zero-cost abstraction. Triggers: E0277, E0308, E0599, generic, trait, impl, dyn, where, monomorphization, static dispatch, dynamic dispatch, impl Trait, trait bound not satisfied, 泛型, 特征, 零成本抽象, 单态化

1 0
View
dojo-world logo
dojoengine/book

dojo-world

Manage world permissions, namespaces, resource registration, and access control. Use when configuring world ownership, setting up authorization policies, or managing resource permissions.

53 0
View

Integrate Cartridge's Verifiable Random Function (VRF) for provably fair, atomic randomness in Dojo games.

53 0
View
dojo-client logo
dojoengine/book

dojo-client

Integrate Dojo with game clients for JavaScript, Unity, Unreal, Rust, and other platforms. Generate typed bindings and connection code. Use when connecting frontends or game engines to your Dojo world.

53 0
View
dojo-deploy logo
dojoengine/book

dojo-deploy

Deploy Dojo worlds to local Katana, testnet, or mainnet. Configure Katana sequencer and manage deployments with sozo. Use when deploying your game or starting local development environment.

53 0
View
dojo-test logo
dojoengine/book

dojo-test

Write tests for Dojo models and systems using spawn_test_world, cheat codes, and assertions. Use when testing game logic, verifying state changes, or ensuring system correctness.

53 0
View
dojo-migrate logo
dojoengine/book

dojo-migrate

Manage world migrations, handle breaking changes, and upgrade Dojo versions. Use when updating deployed worlds, migrating to new versions, or handling schema changes.

53 0
View
dojo-init logo
dojoengine/book

dojo-init

Initialize new Dojo projects with proper directory structure, configuration files, and dependencies. Use when starting a new Dojo game project or setting up the initial project structure.

53 0
View
dojo-config logo
dojoengine/book

dojo-config

Configure Scarb.toml, dojo profiles, world settings, and dependencies. Use when setting up project configuration, managing dependencies, or configuring deployment environments.

53 0
View

Popular AI tools

Kaiber logo
Video

Kaiber

Generate, edit, and beat-sync AI video with leading models in one workspace.

Paid
View
Vimcal logo
Productivity

Vimcal

The world's fastest calendar for remote work

Free
View

Transform Your Design with AI Designer by ImgCreator.ai

Freemium
View
Akool AI logo
Content & writing

Akool AI

Revolutionizing Video Production with AI-Powered Creativity

Paid
View

Extend an image past the frame and let AI fill the new aspect ratio.

Freemium
View
StarByFace logo
Security

StarByFace

Discover your celebrity doppelgänger with StarByFace!

Free
View
C

ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.

Freemium
View
Opus Clip logo
Coding & apps

Opus Clip

Opus.ai: Revolutionize Your Web Experience

Free
View