> For the complete documentation index, see [llms.txt](https://docs.dimes.fi/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.dimes.fi/for-developers/getting-started/react-hooks.md).

# React Hooks

The `@dimes-dot-fi/sdk/react` entry point ships hooks for every read endpoint, two quote flows, and live WebSocket streams. They are thin wrappers over [TanStack Query](https://tanstack.com/query) — every data hook returns a standard `UseQueryResult`, so `data`, `isLoading`, `error`, `refetch`, etc. all work as usual.

Peer dependencies: `react >=19`, `@tanstack/react-query >=5`.

> **Runnable examples:** [`react/trade-panel.tsx`](https://github.com/dimes-fi/dimes-sdk/blob/main/examples/react/trade-panel.tsx) (provider + `useMarkets` + `useQuote`) and [`react/streams.tsx`](https://github.com/dimes-fi/dimes-sdk/blob/main/examples/react/streams.tsx) (`usePositions` with live WebSocket reconciliation). Both are type-checked against the SDK in CI.

## Provider setup

Wrap your app in both a `QueryClientProvider` and `DimesProvider`. The hooks read the `DimesClient` from `DimesProvider` and the query cache from whatever `QueryClientProvider` is in the tree.

```tsx
import { DimesClient, JwtAuth } from "@dimes-dot-fi/sdk";
import { DimesProvider } from "@dimes-dot-fi/sdk/react";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";

const queryClient = new QueryClient();
const client = new DimesClient({
  auth: new JwtAuth({ tokenUrl: "https://your-backend.com/api/dimes-token" }),
});

function Root() {
  return (
    <QueryClientProvider client={queryClient}>
      <DimesProvider client={client}>
        <App />
      </DimesProvider>
    </QueryClientProvider>
  );
}
```

***

## Data hooks

| Hook                                   | Returns             | Endpoint                                |
| -------------------------------------- | ------------------- | --------------------------------------- |
| `useMarkets(params?, qo?)`             | `Paginated<Market>` | `GET /markets` (pass `query` to search) |
| `useMarket(ticker, qo?)`               | `Market`            | `GET /markets/:ticker`                  |
| `usePositions(params?, qo?, options?)` | `Position[]`        | `GET /positions`                        |
| `useContractInfo(qo?)`                 | `ContractInfo`      | `GET /contract-info`                    |
| `useLimits(qo?)`                       | `CustomerLimit`     | `GET /limits`                           |

`qo` is an optional partial `UseQueryOptions` passed straight through (override `enabled`, `staleTime`, etc.).

```tsx
import { useMarkets, usePositions } from "@dimes-dot-fi/sdk/react";

function Markets() {
  const { data, isLoading } = useMarkets({ status: "active", sort: "depth_desc" });
  if (isLoading) return <Spinner />;
  return <>{data!.data.map((m) => <MarketCard key={m.id} market={m} />)}</>;
}
```

### `usePositions` options

The third argument tunes polling and cache behaviour — all opt-in, all off by default:

```tsx
usePositions(
  { state: "active" },
  { enabled: !!wallet },               // standard query options
  {
    scope: wallet?.toLowerCase(),       // append to the cache key — avoids serving a previous wallet's positions
    adaptivePolling: true,              // poll fast (5s) while any position is transitioning, slow (15s) otherwise
    reconcile: true,                    // defer to fresher WebSocket data (pair with usePositionStream reconcile)
  },
);
```

`adaptivePolling` also accepts `{ fastMs, slowMs }`; `reconcile` also accepts a window in milliseconds.

***

## Quote hooks

Two flows sit on the same draft → promote pipeline. Pick by how much control your UI needs over the steps.

### `useQuote` — one-shot

Runs draft → promote (with auto-retry on market-moved and auto-correction of leverage/collateral/slippage) in a single call. Best when you just want a signed quote back and surface progress from `state.phase`.

```tsx
import { useQuote } from "@dimes-dot-fi/sdk/react";

const { state, execute } = useQuote();

const result = await execute(
  { marketTicker, side, collateralUsd, leverageBps, slippageBps },
  {
    onMarketMoved: () => true,   // return false to abort the retry
    onCorrection: () => true,    // return false to reject the adjustment
  },
);
// result.quote is the signed quote; state.phase walks idle → loading-draft → … → promoted
```

### `useQuoteMachine` — interactive

The granular, user-in-the-loop flow: fetch a draft, let the user review it, then promote — pausing across renders at each step. On a market-moved promote failure it re-drafts and surfaces a `market-moved` state so the user can review and **accept** the new draft before it's promoted.

```tsx
import { useQuoteMachine } from "@dimes-dot-fi/sdk/react";

const { state, getDraft, promote, acceptChanges, correctAndPromote, reset } = useQuoteMachine();

// 1. fetch + show a draft
await getDraft({ marketTicker, side, collateralUsd, leverageBps, slippageBps });

// 2. user confirms → promote the reviewed draft
if (state.phase === "draft-ready") await promote(state.draft);

// 3a. market moved → show state.newDraft, then on user confirm:
if (state.phase === "market-moved") await acceptChanges(state.newDraft, state.retryCount);

// 3b. a correctable error → apply a hint and promote adjusted params directly
//     (see quoteErrorHint / hintAdjustment in the core SDK)
await correctAndPromote(state.draft, adjustedParams);
```

`state.phase` is one of `idle | loading-draft | draft-ready | promoting | promoted | market-moved | error`. In the `promoted` phase, `state.promotedQuote` is the signed quote.

> Building a fully custom flow instead? The same primitives are public: `client.createDraftQuote()` / `promoteDraftQuote()` / `createQuote()`, `buildQuoteParams()`, and `isMarketMovedError()`.

### Partial fill

Both flows accept partial-fill params. Pass `allowPartialFill: true` (and optionally `minFillBps`) in the quote params to let an order fill below the requested notional rather than rejecting atomically. The correction logic will also auto-raise `minFillBps` to the floor the API returns. See [Partial-open (FAK)](/for-developers/api-and-events/api-reference.md#partial-open-fak).

***

## Stream hooks

`usePositionStream` and `useMarketStream` subscribe to the user WebSocket gateways. Both default to **reconcile** mode — merging events straight into the `usePositions` / `useMarkets` caches so the UI updates live — but you can switch to **raw** mode and handle events yourself. App-specific side effects (toasts, your own stores) go in the callbacks; the SDK never reaches into your app.

```tsx
import { usePositionStream, useMarketStream } from "@dimes-dot-fi/sdk/react";

function LiveUpdates() {
  usePositionStream({
    mode: "reconcile",                       // default — merges into ["dimes","positions"]
    onEvent: (e) => toastPositionEvent(e),   // always called, in both modes
    onNotification: (n) => toast(n.data.message),
  });

  useMarketStream({
    onEvent: (e) => {
      if (e.type === "market.discovered") addToLiveStrip(e.data); // discoveries are never auto-injected
    },
  });

  return null;
}
```

Shared options: `enabled`, `mode` (`"reconcile"` | `"raw"`), `pauseOnHidden` (disconnect while the tab is hidden, default true), `invalidateOnReconnect` (refetch on reconnect to catch missed events, default true), and the `onEvent` / `onConnect` / `onDisconnect` / `onError` callbacks (`usePositionStream` adds `onNotification`). Each returns `{ socket, connected }`.

In reconcile mode, market eligibility / max-leverage **deltas** are deep-merged into cached markets (so the constant `minBps` / `stepBps` survive a leverage change); `market.discovered` events are deliberately left for you to route, since injecting them would pollute server-filtered list views.

For the raw protocol, gateways, event types, and payloads, see [WebSocket Events](/for-developers/api-and-events/websocket.md).

***

### What's next

* [API Reference](/for-developers/api-and-events/api-reference.md) — every endpoint and its SDK method
* [WebSocket Events](/for-developers/api-and-events/websocket.md) — the underlying socket protocol
* [On-Chain Integration](/for-developers/wallet-integration/on-chain-integration.md) — turning a signed quote into a position
