skip to Main Content

i have the following react component

function App() {
  const [users, setUsers] = useState(test);
  const [name, setName] = useState("");
  const [amount, setAmount] = useState(0);
  const [total, setTotal] = useState(0);
  const [usersNames, setUsersName] = useState([])
  const addUser = () => {
    setUsers([...users, { name: name, amount: amount }]);
    setName("");
    setAmount(0);
  };

  const calculate = () => {
    const total = users.reduce((acc, user) => acc + user.amount, 0);
    const perPerson = total / users.length
    const newUsers = users.map(user => {
      return {...user, balance: user.amount - perPerson, transactions: []}
    })
    setTotal(total);
    setUsersName(users.map(user => user.name));
    setUsers(newUsers);
    const {debtors, creditors} = distribute(newUsers);
    retribute(debtors, creditors);
  }

  const distribute = (usersList) => {
    const debtors = [];
    const creditors = [];

    usersList.forEach(({name, balance}) => {
      if (balance < 0){
        debtors.push(name);
      }

      if (balance > 0){
        creditors.push(name);
      }
    })

    return {
      debtors: debtors,
      creditors: creditors,
    }
  }

  const retribute = (debtorsList, creditorsList) => {
    const usersUpdated = [];
    debtorsList.forEach(debtorName => {
      const debtorPos = usersNames.indexOf(debtorName);
      const debtor = users[debtorPos];
      creditorsList.forEach(name => {
        if (debtor.balance < 0){
          const creditorPos = usersNames.indexOf(name);
          const creditor = users[creditorPos];
          if (creditor.balance >= debtor.balance * -1){
            creditor.balance -= debtor.balance * -1;
            debtor.transactions.push(`${debtor.name} gives ${creditor.name}: ${debtor.balance * -1}`)
            debtor.balance = 0;
          }
          if (creditor.balance < debtor.balance * -1){
            debtor.balance = debtor.balance + creditor.balance;
            debtor.transactions.push(`${debtor.name} gives ${creditor.name}: ${creditor.balance}`)
            creditor.balance = 0;
          }
        }
      })
      usersUpdated.push(debtor);
    })
    console.log(usersUpdated);
  }
...

The ui is very simple just a 2 inputs (name, amount) a button to add to a list and then another button to trigger the calculate function. The problem i’m confronting is the following: When first-clicking the calculate button i recieve this error:

Uncaught TypeError: Cannot read properties of undefined (reading 'balance')
    at App.jsx:63:20
    at Array.forEach (<anonymous>)
    at App.jsx:62:21
    at Array.forEach (<anonymous>)
    at retribute (App.jsx:59:17)
    at calculate (App.jsx:32:5)
    at HTMLUnknownElement.callCallback2 (react-dom.development.js:4164:14)
    at Object.invokeGuardedCallbackDev (react-dom.development.js:4213:16)
    at invokeGuardedCallback (react-dom.development.js:4277:31)
    at invokeGuardedCallbackAndCatchFirstError (react-dom.development.js:4291:25)

and then, if i clicked it again, it works properly.
I’m very new in React and things are not going as expected. Thanks to whoever reply and try to help me!

2

Answers


  1. Try change this:
    const [users, setUsers] = useState(test);

    to something like:
    const [users, setUsers] = useState([]);

    Login or Signup to reply.
  2. I see that you have functions which set state and do other computations. But that you have not initialized the data for all of your states. Just the users.

    I cannot see your JSX code or the entirety of your component, but I’m going to assume that your functions are invoked only on onClick.

    You have said that on initial button click, an error thrown. But not on the second click.

    This is possibly because of calculate function is called somewhere in your code when the button is clicked. Which sets all of your states.

    You could probably fix this issue by properly setting up data for your different states on component mount. This would be the recommended way.

    …But you could also probably call your calculate function inside a useEffect, to set up your states on component mount.

    useEffect(() => {
      calculate();
    }, [])
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search