Home > Software design >  React: Mapping an array of state objects does not show all state
React: Mapping an array of state objects does not show all state

Time:07-18

I am having the following weird issue, using React. I am building a budget tracker app, which has a total budget, a form to add a new expense and in the end displays the expense with the cost bellow. The new cost is also subtracted from the total budget. I have the following states:

const [total, setTotal] = useState(1500);
const [expense, setExpense] = useState({
     name: "Expense",
     cost: "0"
   });
const [allExpenses, setAllExpenses] = useState([]);

The first one is the total budget. The second state - expense is the new expense, which is added from the form. allExpenses is an array of objects, which needs to be printed out bellow the form.

These are my setter methods, which occur onChange (in the input fields) and onSubmit (submitting the form):

const handleSubmit = event =>{
    event.preventDefault();
    let exp = expense.name;
    let cost = expense.cost;
    alert( "New expense "   exp   " costs "   cost );

    setTotal((prevTotal) => prevTotal - cost);

    const newAll = (prevAll) => ([...prevAll, expense]);
    setAllExpenses(newAll);
  }
  
  const handleChange = event =>{
     setExpense((prevExpense) => ({
     ...prevExpense, 
     [event.target.name]: event.target.value
      }))
  }

And in the render function, bellow the form, I call the array map() function to print out headers with the expense's name and cost.

{allExpenses.map(({item, cost}) => {return <h1>{item} costs {cost}$</h1>})}

I have also added a display component to track whether the state changes.

export function Printer (props){
    return(
        <h1>{props.name} costs {props.cost}$</h1> 
        /*
        Added as a change tracker. State DOES change.
        Issue is probably within the allExpenses state.
        
        */
    );
}

The problem is that the state does change. If I add a new expense - for example NewExpense, 12$, the printer component will display "NewExpense costs 12$". However, the mapping function of the array will display " costs 12$". The state has changed, but the expense.name attribute of the object doesn't show after mapping. Everything else seems to be working fine. I've tried rewriting the map() call and the setAllExpenses state setter. Nothing seems to be fixing the issue, which is quite peculiar. The form is also within the render (not in a separate component), so I am not passing any state through props. What am I missing here?

CodePudding user response:

You need to make changes in array map function as below.

{allExpenses.map(({name, cost}) => {return <h1>{name} costs {cost}$</h1>})}

This should get print "NewExpense costs 12$".

CodePudding user response:

You need to change the allExpenses state correctly.

Instead of this

const newAll = (prevAll) => ([...prevAll, expense]);
setAllExpenses(newAll);

Try this

setAllExpenses((prevAll) => [...prevAll, expense]);
  • Related