Rendering React components asynchronously

Could anyone point me to code examples where React components are rendered based on asynchronously loaded data from the DAML ledger? Eg I want to render a component three times if I have a certain contract three times in the ACS.

We have examples for this using the DAML React hooks in the JS Client-Side libraries (e.g. here), however, I think I need to use the ledger API to query the ACS in my scenario and I think this means I can’t use the same pattern.

---------------------------------------------------------------

I would be happy to be proven wrong though; thus, more details on my use case:

I have a template BuyProposal which presents someone making a public offer for an asset:

template BuyProposal
  with
    buyer: Party
    iou: ContractId Iou
    asset: Asset
    public: Party 
  where
    signatory buyer
    observer public

     nonconsuming ShowIouToPublic: Iou
        do
          fetch iou

An Iou template looks like this (details omitted):

template Iou with
    issuer : Party
    owner : Party
    amount: Decimal

I now want to list all public buy proposals (including details of the offered Iou) in my Frontend.

I think the only way to achieve this, is to first query the ContractIds of all BuyProposal contracts (from the context of the public party):
const cids = publicContext.useStreamQueries(Main.BuyProposal).contracts.map(prop => prop.contractId)

and then use the ledger API to exercise the ShowIouToPublic choice to get the corresponding Ious:

const ledger = publicContext.useLedger();
async function getIous (cids: ContractId<Main.BuyProposal []){
      for (const cid of cIds){
        const iou = await ledger.exercise(Main.BuyProposal.ShowIouToPublic, cid, []);
      }
    }

getIous(cids)

At this point, I’m unsure how to make use of the values of the Ious (e.g. the amount) since getIous returns a promise and I don’t know how to use a promise for rendering a component - hence the question.

Any help would be appreciated - apologies for the long post (and for this being more of a React than DAML question)!

1 Like

No need to apologize, writing only backends in Daml with no frontends wouldn’t work in lots of cases. As long as a technical question involves Daml it belongs on the forum.

2 Likes

I think I’d use the State Hook for that. Ie do something like

const [ious, setIous] = useState([]);

Then call setState([iou]) inside your getIous.

Or possibly the Effect Hook?

2 Likes

Thanks Bernhard! That hint pointed me in the right direction and I was able to figure it out with the aid of this post.

What I essentially ended up doing in my React code is:

const ledger = publicContext.useLedger();
const [ious, setIous] = useState(([] as Iou[]));

const cids = publicContext.useStreamQueries(BuyProposal).contracts.map(prop => prop.contractId)
const loadIous = (cids: ContractId<BuyProposal> []) => {
      const ious = cids.map(async cid => 
          const iou = await ledger.exercise(BuyProposal.ShowIouToPublic, cid, []).then(res => res[0]);
          return iou;
        }
      Promise.all(ious)
      .then((ious) => setIous(ious));
    }
useEffect(loadIous(cids), [cids]);

I was then able to simply use the state ious to, e.g., simply create a list of the Iou values:

return (
    <ul>
      {ious.map(item => (
        <li>
          Iou amount: {item.amount}
        </li>
      ))}
    </ul>
  );

3 Likes