如何在 React Hooks 的对象数组中更新状态 `onChange`

How do I update states `onChange` in an array of object in React Hooks

我检索了使用 useState 存储在对象数组中的数据,然后将数据输出到表单字段中。现在我希望能够在输入时更新字段(状态)。

我看到有人更新数组中 属性 的状态的示例,但从来没有更新对象数组中的状态,所以我不知道该怎么做。我已将对象的索引传递给回调函数,但我不知道如何使用它更新状态。

// sample data structure
const datas = [
  {
    id: 1,
    name: 'john',
    gender: 'm'
  }
  {
    id: 2,
    name: 'mary',
    gender: 'f'
  }
]

const [datas, setDatas] = useState([]);

const updateFieldChanged = index => e => {
  console.log('index: ' + index);
  console.log('property name: '+ e.target.name);

  setData() // ??
}

return (
  <React.Fragment>
    {datas.map((data, index) => {
      <li key={data.name}>
        <input type="text" name="name" value={data.name} onChange={updateFieldChanged(index)} />
      </li>
    })}
  </React.Fragment>
)

操作方法如下:

// sample data structure
/* const data = [
  {
    id:   1,
    name: 'john',
    gender: 'm'
  }
  {
    id:   2,
    name: 'mary',
    gender: 'f'
  }
] */ // make sure to set the default value in the useState call (I already fixed it)

const [data, setData] = useState([
  {
    id:   1,
    name: 'john',
    gender: 'm'
  }
  {
    id:   2,
    name: 'mary',
    gender: 'f'
  }
]);

const updateFieldChanged = index => e => {
  console.log('index: ' + index);
  console.log('property name: '+ e.target.name);
  let newArr = [...data]; // copying the old datas array
  newArr[index] = e.target.value; // replace e.target.value with whatever you want to change it to

  setData(newArr);
}

return (
  <React.Fragment>
    {data.map((datum, index) => {
      <li key={datum.name}>
        <input type="text" name="name" value={datum.name} onChange={updateFieldChanged(index)}  />
      </li>
    })}
  </React.Fragment>
)

您可以通过将旧数组映射到新数组,并在此过程中将您想要更改的内容换成更新的项目,从而在不进行突变的情况下执行此操作。

setDatas(
    datas.map(item => 
        item.id === index 
        ? {...item, someProp : "changed"} 
        : item 
))

我是这样做的:

const [datas, setDatas] = useState([
  {
    id: 1,
    name: "john",
    gender: "m",
  },
  {
    id: 2,
    name: "mary",
    gender: "f",
  },
]);

const updateFieldChanged = (name, index) => (event) => {
  let newArr = datas.map((item, i) => {
    if (index == i) {
      return { ...item, [name]: event.target.value };
    } else {
      return item;
    }
  });
  setDatas(newArr);
};

return (
  <React.Fragment>
    {datas.map((data, index) => {
      <li key={data.name}>
        <input
          type="text"
          name="name"
          value={data.name}
          onChange={updateFieldChanged("name", index)}
        />
      </li>;
      <li key={data.gender}>
        <input
          type="text"
          name="gender"
          value={data.gender}
          onChange={updateFieldChanged("gender", index)}
        />
      </li>;
    })}
  </React.Fragment>
);

您甚至不需要使用索引(如果需要,可以使用键除外),也不需要复制旧数据数组,甚至可以内联或将数据作为参数传递,如果您更喜欢 updateFieldChanged不是内联的。这样很快就完成了:

  const initial_data = [
    {
      id: 1,
      name: "john",
      gender: "m",
    },
    {
      id: 2,
      name: "mary",
      gender: "f",
    },
  ];

  const [datas, setDatas] = useState(initial_data);

  return (
    <div>
      {datas.map((data, index) => (
        <li key={index}>
          <input
            type="text"
            value={data.name}
            onChange={(e) => {
              data.name = e.target.value;
              setDatas([...datas]);
            }}
          />
        </li>
      ))}
    </div>
  );
};

基于@Steffan,按照您的方式使用:

const [arr,arrSet] = useState(array_value);
...
let newArr = [...arr];
  arr.map((data,index) => {
    newArr[index].somename= new_value;
  });
arrSet(newArr);

使用 useEffect 检查新的 arr 值。

setDatas(datas=>({
   ...datas,
   [index]: e.target.value
}))

索引为目标位置,e.target.value新值

聚会有点晚了,但是可以选择将数组的内容散布在一个新对象中,然后替换所选索引中的所需对象,最后从该结果生成一个数组,它是简短的回答,可能不是大型阵列的最佳选择。

// data = [{name: 'tom', age: 15, etc...}, {name: 'jerry', age: 10, etc...}]
// index = 1
setData(Object.values({...data, [index]: {...data[index], name: 'the mouse' }}))
// data = [{name: 'tom', age: 15, etc...}, {name: 'the mouse', age: 10, etc...}]

在此之前展开阵列。因为你不能不使用 useState

返回的方法直接更新钩子
const newState = [...originalState]
newState[index] = newValue
setOriginalState(newState)

如果它是一个字符串数组,这将修改状态的值并更新 useState 挂钩。

const updateFieldChanged = index => e => {
   
   name=e.target.name //key
  
   let newArr = [...data]; // copying the old datas array
   newArr[index][name] = e.target.value; //key and value
   setData(newArr);
}

return (
  <React.Fragment>
    {data.map((datum, index) => {
      <li key={datum.name}>
        <input type="text" name="name" value={datum.name} onChange={updateFieldChanged(index)}  />
      </li>
    })}
  </React.Fragment>
)