Hi I am working on a expense tracker I've honestly been stuck on for way too long. I am trying to render my Expense component multiple times. I know I need to .map it so I am not sure how I am supposed to go about it from where I am at. Any help would be amazing, I am having trouble really breaking through into react. I feel like I'm right there even though I'm struggling on this basic app.
const initialValues = {payment: '', purchase: '', date:'', location: '', price: ''};
const [formValues, setFormValues] = useState([initialValues]);
const onHandleChange = (e) => {
const value = e.target.value;
setFormValues({...formValues,
[e.target.name]: value
});
}
Below is how I'm trying to render multiple of my expense component
const userRows = Object.keys(formValues).map((value) =>{
<Expense formValues={value} />
})
console.log(userRows)
return(
<table className="expense-container">
<tbody className='expense-list'>
{userRows}
And below this is my expense component
return(
<tr className='tableRow expense'>
<td className="mr-2">{formValues.payment}</td>
<td className="mr-1">{formValues.purchase}</td>
<td className="mr-1">{formValues.date}</td>
<td className="mr-1">{formValues.location}</td>
<td className="mr-1">{formValues.price}</td>
</tr>
)
Like Diego said you are missing a return statement from the userRows map function. And when you are passing in the formValue prop into the Expense component, you are only passing in a key from the object, not the object itself. This is because you are mapping over the keys of the object. Also, you are initializing your formValues state as an array with an object inside. But in your handleChange function you are setting the state to an object.
I'm not sure how the rest of your code is structured, but I assume you are trying to have a form where a user can submit a new expense. Instead of using the same state for the form and the expenses, you should split them up into two separate states. Like this.
const initialValues = {payment: '', purchase: '', date:'', location: '', price: ''}
const [formValues, setFormValues] = useState(initialValues);
const [expenses, setExpenses] = useState([])
const onHandleChange = (e) => {
const value = e.target.value;
setFormValues({...formValues,
[e.target.name]: value
});
}
const onSubmit = () => {
// Append new expense to the expenses array
setExpenses(previousExpenses => [...previousExpenses, formValues]);
// Reset Form
setFormValues(initialValues);
}
You could use parenthesis to immediately return from the map method.
// map over the expenses array and create a component based on each object in the array
const userRows = expenses.map((expenseObject) =>(
<Expense formValues={expenseObject} />
))
Or just use a return statement.
// map over the expenses array and create a component based on each object in the array
const userRows = expenses.map((expenseObject) =>{
return (<Expense formValues={expenseObject} />)
})
Also make sure in your Expense component that you are destructuring the props to get the formValues prop, which I assume is what you are doing.