Skip to content

Commit

Permalink
Implement useEvents hook (#547)
Browse files Browse the repository at this point in the history
Add a new hook `useEvents` that supports fetching Starknet events continuously.


Closes #465
  • Loading branch information
fracek authored Jan 12, 2025
2 parents aabead6 + 4cd32f1 commit fa5667b
Show file tree
Hide file tree
Showing 11 changed files with 649 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "minor",
"comment": "Implement useEvents hook",
"packageName": "@starknet-react/core",
"email": "[email protected]",
"dependentChangeType": "patch"
}
80 changes: 80 additions & 0 deletions docs/components/demo/events.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { useBlockNumber, useEvents, useNetwork } from "@starknet-react/core";
import stringify from "safe-stable-stringify";
import { DemoContainer } from "../starknet";
import { Button } from "../ui/button";
import { BlockTag } from "starknet";

function EventsInner() {
const eventName = "Transfer";
const { chain } = useNetwork();
const address = chain.nativeCurrency.address;
const fromBlock = useBlockNumber().data - 10;
const toBlock = BlockTag.LATEST;

const pageSize = 3;
const {
data,
error,
fetchNextPage,
hasNextPage,
isFetchingNextPage,
status,
} = useEvents({ address, eventName, fromBlock, toBlock, pageSize });

const response =
status === "pending" ? (
<p>Loading first events ...</p>
) : status === "error" ? (
<>
<p>Error: {error?.message}</p>
<pre>{stringify({ data, error }, null, 2)}</pre>
</>
) : (
<>
<div>
<Button
onClick={() => fetchNextPage()}
disabled={!hasNextPage || isFetchingNextPage}
>
{isFetchingNextPage
? "Loading more events ..."
: hasNextPage
? "Load more events"
: "No more events to load"}
</Button>
</div>

{data?.pages
.slice(0)
.reverse()
.map((page, i) => (
<div key={page.continuation_token}>
<p>Chunk: {data.pages.length - i}</p>
<pre>{stringify({ page }, null, 2)}</pre>
</div>
))}
</>
);

return (
<div className="flex flex-col gap-4">
<p>Fetching events for</p>
<pre>
{stringify(
{ address, eventName, fromBlock, toBlock, pageSize },
null,
2,
)}
</pre>
{response}
</div>
);
}

export function Events() {
return (
<DemoContainer hasWallet>
<EventsInner />
</DemoContainer>
);
}
3 changes: 3 additions & 0 deletions docs/components/demo/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import { StarkProfile } from "./stark-profile";
import { StarknetKit } from "./starknetkit";
import { SwitchChain } from "./switch-chain";
import { WalletPermission } from "./wallet-permission";
import { Events } from "./events";

export default {
Account,
WalletPermission,
Expand All @@ -33,4 +35,5 @@ export default {
StarknetKit,
ChangeDefaultNetwork,
DeployContract,
Events,
};
12 changes: 12 additions & 0 deletions docs/pages/demo/events.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import Demo from "../../components/demo";

# Events

<Demo.Events />

This demo shows how to fetch events continuously.

[Link to GitHub](https://github.com/apibara/starknet-react/blob/main/docs/components/demo/events.tsx)

Hook(s)
- `useEvents`
2 changes: 2 additions & 0 deletions docs/pages/demo/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ You can find the source code for these demos [on GitHub](https://github.com/apib

**[Change Default Network](/demo/change-default-network)**: Shows how to change the default network.

**[Events](/demo/events)**: Shows how to fetch events continuously.

## New APIs

**[Request wallet permissions](/demo/wallet-permission)**: Shows how to request wallet permissions.
Expand Down
149 changes: 149 additions & 0 deletions docs/pages/docs/hooks/use-events.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
# useEvents

Fetch Starknet events continuously

By default this hook tries to fetches all the events (5 events per page) starting from genesis but you can pass arguments for filtering

## Usage

Fetch ETH Transfer events:

```ts twoslash
import { useEvents } from "@starknet-react/core";

const {
data,
error,
fetchNextPage,
hasNextPage,
isFetchingNextPage,
} = useEvents(
{
address: "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7",
eventName: "Transfer",
fromBlock: 442920,
toBlock: "latest",
pageSize: 10
}
);
```

## Arguments

### address

- Type: `Address | undefined`

Filter events emitted by a specific contract address

### eventName

- Type: `string | undefined`

Filter events using an event name, e.g "Transfer".

### fromBlock

- Type: `BlockIdentifier | undefined`

The `BlockIdentifer` type from `starknet` excluding `bigint`

Start fetching events from this block, e.g 44920.

### toBlock

- Type: `BlockIdentifier | undefined`

The `BlockIdentifer` type from `starknet` excluding `bigint`

Stop fetching events at this block, e.g `BlockTag.LATEST`.

### pageSize

- Type: `number | undefined`

The number of events returned from each individual query, default to 5.

## Returns

### data

- Type: `InfiniteData<Events, string>`
```
InfiniteData<Events, string> = {
pages: Array<Events>; // Array containing all pages.
pageParams: Array<string>; // Array containing all page params.
}
```

The `InfiniteData` type from `react-query` and the `Events` type from `starknet`.

### hasNextPage

- Type: `boolean`

Will be true if there is a next page to be fetched

### isFetchingNextPage

- Type: `boolean`

Will be true while fetching the next page with `fetchNextPage`.

### fetchNextPage

- Type: `(options?: FetchNextPageOptions) => Promise<UseEventsResult>`

`UseEventsResult` is the same return type of the `useEvents` hook

This function allows you to fetch the next page of events, make sure to check `isFetchingNextPage` and `hasNextPage` before calling it.

If `options.cancelRefetch: boolean` is set to true, calling `fetchNextPage` repeatedly will fetch events every time, whether the previous invocation has resolved or not. Also, the result from previous invocations will be ignored. If set to false, calling `fetchNextPage` repeatedly won't have any effect until the first invocation has resolved. Default is true.

### error

- Type: `Error | null`

Any error thrown by the query.

### status

- Type: `"error" | "pending" | "success"`

The query status.

- `pending`: the query is being executed.
- `success`: the query executed without an error.
- `error`: the query threw an error.

### isError

- Type: `boolean`

Derived from `status`.

### isPending

- Type: `boolean`

Derived from `status`.

### isSuccess

- Type: `boolean`

Derived from `status`.

### fetchStatus

- Type: `"fetching" | "paused" | "idle"`

- `fetching`: the query is fetching.
- `paused`: the query is paused.
- `idle`: the query is not fetching.

### isFetching

- Type: `boolean`

Derived from `fetchStatus`.
4 changes: 4 additions & 0 deletions docs/sidebar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,10 @@ export const sidebar = {
text: "useTransactionReceipt",
link: "/docs/hooks/use-transaction-receipt",
},
{
text: "useEvents",
link: "/docs/hooks/use-events",
},
],
},
{
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,4 @@ export * from "./use-transaction-receipt";
export * from "./use-wallet-request";
export * from "./use-watch-asset";
export * from "./use-universal-deployer-contract";
export * from "./use-events";
Loading

0 comments on commit fa5667b

Please sign in to comment.