[英]How to update an existing array of objects (add a new object to the array) with the useState hook?
I have an onChange handler with which I can edit certain objects with input fields.我有一个 onChange 处理程序,我可以使用它编辑带有输入字段的某些对象。
The onChange handler looks like this: onChange 处理程序如下所示:
// First I get the current state
const [persons, setPersons] = useState(service.persons);
The API returns the following for persons (an array of objects): API 为人员(对象数组)返回以下内容:
contacts (2) [{…}, {…}]
0: {person_company: "Google", person_name: "John Doe"}
1: {person_company: "Facebook", person_name: "Jane Doe"}
My onChange handler looks like this (..first part of the if statement for editing the given persons works perfectly, but the else statement for creating a new person doesn't):我的 onChange 处理程序看起来像这样(.. 用于编辑给定人员的 if 语句的第一部分可以完美运行,但用于创建新人员的 else 语句则不能):
const updatePersons = (e: any, index?: number) => {
if (index !== undefined) {
const updatedPersons = [...persons];
updatedPersons[index][e.target.name] = e.target.value;
setPersons(updatedPersons);
} else {
setPersons({ ...persons, [e.target.name]: e.target.value });
}
};
My template looks like this (just empty input fields for creating a new person with a person_company and person_name):我的模板看起来像这样(只是空的输入字段用于创建一个带有 person_company 和 person_name 的新人):
<InputContainer>
<p>New person</p>
<InputWrapper>
<TextField
type="text"
label="Person company"
name='person_company'
value=' '
onChange={e => updatePersons(e)}
/>
</InputWrapper>
<InputWrapper>
<TextField
type="text"
label="Person name"
name="person_name"
value=' '
onChange={e => updatePersons(e)}
/>
</InputWrapper>
</InputContainer>
Unfortunately, it doesn't work that way.不幸的是,它不是那样工作的。
Only the first letter is realized in the first input field and the whole component disappears afterwards在第一个输入字段中仅实现第一个字母,然后整个组件消失
If I manipulate it so that the component does not disappear, the value of the input field is not updated (this is probably because I set value = ' '. I have no idea what else I should provide).如果我对其进行操作以使组件不会消失,则输入字段的值不会更新(这可能是因为我设置了 value = ' '。我不知道我还应该提供什么)。
If I console log persons after the first letter as mentioned in 1., the array of object is updated as follows:如果我在 1. 中提到的第一个字母之后控制台记录人员,则 object 的数组更新如下:
contacts {0: {…}, 1: {…}, company_name: " t"} 0: {person_company: "Google", person_name: "John Doe"} 1: {person_company: "Facebook", person_name: "Jane Doe"} person_company: " t"
But my goal is that the object should be updated as follows when I create a new person:但我的目标是当我创建一个新人时,object 应该更新如下:
contacts (3) [{…}, {…}, {…}]
0: {person_company: "Google", person_name: "John Doe"}
1: {person_company: "Facebook", person_name: "Jane Doe"}
2: {person_company: "Amazon", person_name: "Max Mustermann"}
What am I doing wrong here?我在这里做错了什么?
try this dont spread a list inside of object, and instead spread a list and add object, also because when you call a new person there is no index provided:试试这个不要在 object 内传播列表,而是传播一个列表并添加 object,也是因为当你打电话给新人时没有提供索引:
const updatePersons = (e: any, index?: number) => {
if (index !== undefined) {
const updatedPersons = [...persons];
updatedPersons[index][e.target.name] = e.target.value;
setPersons(updatedPersons.map((person)=>({...person,new:false})));
} else {
const lastPerson = persons.slice(-1)[0];
if (lastPerson.new){
setPersons([...persons.slice(0,-1), {...lastPerson ,[e.target.name]:e.target.value}]);
} else {
setPersons([...persons,{[e.target.name]:e.target.value , new:true}]
}
}
};
Unfortunately, I couldn't solve it using the approaches suggested.不幸的是,我无法使用建议的方法解决它。 But I did it in a different way.
但我以不同的方式做到了。
I adapted the updatePersons method, which now only processes the cases with an ID (so no else block anymore).我调整了 updatePersons 方法,该方法现在只处理带有 ID 的案例(因此不再有 else 块)。
const updatePersons = (e: any, index?: number) => {
e.preventDefault(); // is this needed here?
if (index !== undefined) {
const updatedPersons = [...persons];
updatedPersons[index][e.target.name] = e.target.value;
setPersons(updatedPersons);
}
};
Instead, I now do everything directly in the onChange handler of the textfields to create a new person.相反,我现在直接在文本字段的 onChange 处理程序中执行所有操作来创建一个新人。
// I created another useState hook for the new Person
// ..and provided an initial state (empty strings) by instantiating a new Person:
const [newPerson, setNewPerson] = useState(new Person());
My textfields now look like this:我的文本字段现在看起来像这样:
<InputWrapper>
<TextField
type="text"
label="Person name"
name="person_name"
value=' '
onChange={e => setNewPerson({ ...newPerson, [e.target.name]: e.target.value })}
/>
</InputWrapper>
I have also created a submit handler in which I update the state and empty the form fields afterwards.我还创建了一个提交处理程序,在其中更新 state 并随后清空表单字段。
const submitHandler = (e: any) => {
e.preventDefault(); // is this needed here?
setPersons([...persons, newPerson]);
setNewPerson(new Person()); // Empty the form fields
};
Let me know if this solution is also ok.让我知道这个解决方案是否也可以。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.