Track 6 · dApps & frontend · lesson 6
Listening to events
10 min
Track 4 taught you to emit events. Track 1 said history lives in logs, not storage. This lesson is the other end of that: reading those events from a frontend to keep a UI honest.
A dApp has two jobs with events: show what already happened (history), and react to what happens while the user watches (live updates). viem does both, and both read from the logs your contracts emit.
Past events
const logs = await client.getLogs({
address: token,
event: parseAbiItem(
"event Transfer(address indexed from, address indexed to, uint256 value)",
),
args: { to: userAddress }, // only transfers TO this user
fromBlock: "earliest",
});
args filters on the indexed parameters — the reason to was marked
indexed back in track 4. Filtering on a non-indexed field is not possible at
the node level; you would have to fetch everything and filter in JavaScript.
Live events
const unwatch = client.watchContractEvent({
address: token,
abi: erc20Abi,
eventName: "Transfer",
onLogs: (logs) => {
for (const log of logs) refreshRow(log.args);
},
});
// call unwatch() when the component unmounts
This is how a UI updates the instant something happens on-chain, without the user reloading.
Predict
You want to show a user only the NFTs sent to them, efficiently. What made that query cheap?
When events are not enough
For anything beyond a simple query — totals, joins across contracts, ordering by computed fields — teams run an indexer (The Graph, Ponder, or a custom one) that ingests events into a database the frontend queries with GraphQL or SQL.
The rule of thumb: direct getLogs for simple, recent history; an indexer when
you need to ask real questions of a lot of data.
Check
Why can't you filter `getLogs` on a non-indexed event parameter at the node?
Worth remembering
- A dApp reads events for history (getLogs) and live updates (watchContractEvent).
- You can filter cheaply only on indexed parameters — the topics from track 4.
- Non-indexed values live in the data blob and can't be filtered at the node.
- Which parameters you index determines what the frontend can query efficiently.
- For complex queries over lots of data, run an indexer rather than raw getLogs.