Collectives™ on Stack Overflow
Find centralized, trusted content and collaborate around the technologies you use most.
Learn more about Collectives
Teams
Q&A for work
Connect and share knowledge within a single location that is structured and easy to search.
Learn more about Teams
I am trying to map out the values in a state to make a dynamic input list. However, I am not quite sure how to correctly map it out. Any help would be greatly appreciated, thanks.
This is what I got:
import React, { useState } from "react";
const Values = () => {
const [values, setValues] = useState([
{ name: "sean", income: 0, spending: 0, investment: 0 },
{ name: "bobby", income: 0, spending: 0, investment: 0 },
{ name: "katie", income: 0, spending: 0, investment: 0 },
{ name: "mary", income: 0, spending: 0, investment: 0 },
{ name: "elly", income: 0, spending: 0, investment: 0 },
const allIncome = "adding up all the values of income here";
return (
<form className="box">
{values.map(() => (
<div className="container">
<div>{values.name}</div>
<input
type="number"
value={values.income}
onChange={(e) => setValues({ income: e.target.value })}
<input
type="number"
value={values.spending}
onChange={(e) => setValues.apply({ spending: e.target.value })}
<input
type="number"
value={values.investment}
onChange={(e) => setValues({ investment: e.target.value })}
<input type="submit" />
</form>
export default Values;
For situations like this I recommend using a Higher Order Function to close over an id
property, or an index if you aren't deleting or sorting records, in an onChange
callback so you can uniquely identify the array element you want to update. From here you use the typical input name
and value
to apply the update.
Example:
const changeHandler = index => event => {
const { name, value } = event.target;
setValues(values => values.map((el, i) => index === i
...el,
[name]: value,
: el,
When mapping the data you attach the callback and pass the current index. You should reference the current value
element when passing/setting the value
prop on each input, referencing the nested property of each data element. Don't forget to add a React key to the outermost mapped element
<form className="box">
{values.map((value, index) => ( // <-- current element value and index
key={index} // <-- add React key
className="container"
<div>{value.name}</div> // <-- reference from current value
<input
type="number"
name="income" // <-- name matches state field
value={value.income}
onChange={changeHandler(index)} // <-- add callback, pass current index
<input
type="number"
name="spending"
value={value.spending}
onChange={changeHandler(index)}
<input
type="number"
name="investment"
value={value.investment}
onChange={changeHandler(index)}
<input type="submit" />
</form>
Ideally, your data would have a dedicated GUID, such as an id
property. This is preferable to using the index as the index isn't an intrinsic property of your data. The reason being is that now you can delete, sort, etc... the values
array and the React key being the id
of the element React can optimize rerendering the UI. See Lists & Keys for more in-depth explanation.
Updater using an id property:
const changeHandler = id => event => {
const { name, value } = event.target;
setValues(values => values.map((el) => el.id === id
...el,
[name]: value,
: el,
<form className="box">
{values.map((value) => ( // <-- current element value
key={value.id} // <-- add React key
className="container"
<div>{value.name}</div> // <-- reference from current value
<input
type="number"
name="income"
value={value.income}
onChange={changeHandler(value.id)} // <-- add callback, pass current id
<input
type="number"
name="spending"
value={value.spending}
onChange={changeHandler(value.id)}
<input
type="number"
name="investment"
value={value.investment}
onChange={changeHandler(value.id)}
<input type="submit" />
</form>