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>