Getting the list of users within React

Hi, I want to show a list of ledger users in a React UI. I tried this:

const [users, setUsers] = useState<User[]>([]);
useEffect(() => {userContext.useLedger().listUsers().then(users=>setUsers(users))},[]);

But this fails with an invalid hook call, which I think is because I cannot use userContext within useEffect.

Can anyone give me a steer please on how I can successfully populate users? Thanks.

I haven’t tried this but how about this:

const [users, setUsers] = useState<User[]>([]);
const ledger = userContext.useLedger();
useEffect(() => {ledger.listUsers().then(users=>setUsers(users))},[])

I also want to point out that listUsers requires admin claims. Do not use this in contexts where you expect to only have claims for an individual user that is not an admin.

1 Like

Yes that fixed it thanks. I tried something similar with async and await but obviously didn’t get it quite right.

The code works fine on the Canton sandbox where of course by default there is no request authorization. But taking your point about the need for admin claims I guess the use of alias contracts (as at the end of this post) may be a better approach.

My recommendation is to consider auth from the beginning when you build a Daml app. You can ofc use a shared secret or something similar to make up tokens on the fly like create-daml-app does but being explicit about the claims is really important to make sure you can later run your app in an authorized ledger without requiring fundamental redesigns.

As for users, there is another issue if you want to use it as a replacement for alias contracts: The users are local to one participant. So you also wouldn’t be able to distribute your app.

The alias contracts are a good option if you need a mapping of human readable names to party ids that works in an authorized, distributed setting.

1 Like

and just a little info here How to use async functions in useEffect (with examples) - Devtrium

React.useEffect can’t take a function that returns a promise. You would need to define the async function from inside the useEffect. You could also extract it (shown in the article above) but below is just a rough example of using async / await

// UserList.tsx

const ledger = userContext.useLedger()
const [users, setUsers] = React.useState<User[] | undefined>(undefined);
React.useEffect( () => {
     // defining the async function inside the useEffect
   const getUsers = async () => {
      try {
        const  result = await ledger.listUsers();
      } catch (e) {
        return {isOk: false, payload: e}
    // calling the defined function above
  }, [])
  console.log('users', users)