Using @daml/ledger with React Class Components

I prefer React class-based components and so am migrating my app (currently based on daml-ui-template) to use class-based components. I hence cannot use hooks. i was wondering if there were any examples of the usage of ledger.streamQuery such that it behaved similarly to useStreamQuery. Thanks!

For example, from the daml-ui-template

export default function Report() {
  const classes = useStyles();
  const party = useParty();
  const ledger = useLedger();
  const assets = useStreamQuery(Asset).contracts;
...
        <TableBody>
          {assets.map((a, i) => (
            <TableRow key={i} className={classes.tableRow}>
...

How could I do this same thing without hooks, and with class components?

Hi @alex_m,
I think you would have to write a class that maintains its own ledger object and also the state of the stream. Basically you would have to re-implement the useStreamQuery function like here as a class component. In that piece of code you also see how ledger.streamQuery is used.

I hope that helps!

1 Like

Looks promising! I’ll have a mess around and let you know.

I think I would in fact have to maintain a Stream object. The problem I am encountering is that Stream is a generic type and the actual type signature of the Stream (as returned from my ledger.streamQuery(TransportationRecord) is very ugly. Something like:
Stream<TransportationRecord, undefined, "827c178267266bb80711c560783b5391b5a3a45035176e251689366b6ce2ee85:Records:TransportationRecord", readonly CreateEvent<TransportationRecord, undefined, "827c178267266bb80711c560783b5391b5a3a45035176e251689366b6ce2ee85:Records:TransportationRecord">[]>.
I’d rather not refer to it as any.

I am thinking of setting stream.on(...) stuff in componentDidMount and then closing the stream on componountWillUnmount

Solved my problem with:
const getStream = (ledger: Ledger) => ledger.streamQuery(TransportationRecord);

private stream: ReturnType<typeof getStream> | undefined = undefined;

1 Like

Are you sure you need to maintain a stream object in your class? I would have expected that you maintain a QueryResult object in your class and issue a ledger.streamQuery on creation of the class instance. You then get a stream back where you register your callbacks to update the QueryResult.

Yeah I think so. Wouldn’t you need to maintain a reference to the stream such that you can call close on componentWillUnmount?

I would have expected that you maintain a QueryResult object in your class and issue a ledger.streamQuery on creation of the class instance

… So in the constructor? Can React components do fetchy things in a constructor?

I think you want to hook into two of the React lifecycle methods, namely componentDidMount and componentWillUnmount. Subscribe in the former, unsubscribe in the latter.

Not sure, otherwise you could have it as a method. I guess you need the stream object to properly close it.