我对在两种情况下如何使用钩子更新React状态有语法疑问。
1)我有一个叫做company的州和一个填写它的表格。在联系部分中,有两个输入代表公司员工(姓名和电话号码)。但是,如果要联系的公司不止一个员工,则有一个“添加更多联系人”按钮,该按钮必须重复相同的输入(当然,目的是第二个联系人)。我怎样才能做到这一点?我的意思是,要在状态内的数组“联系人”中生成另一个索引,请在具有该数组的对象内增加totalOfContacts并创建输入标签,以便用户可以键入第二个联系人的数据?
2)当我键入任何输入时,代码将触发handleChange函数。 “名称”和“城市”已经更新了状态,因为它们是简单状态。但是,由于联系人姓名和他的电话号码是该州内部数组索引的一部分,我该如何更新呢?
下面的代码已经可以正常工作了,我的两个问题正好是两条注释行(第20和29行)。
“保存”按钮只需控制台即可。记录结果,以便我们对其进行监控。
现在谢谢。
import React, { useState, useEffect } from "react";
export default () => {
const [company, setCompany] = useState({
name: "", city: "",
contact: {
totalOfContact: 1,
contacts: [
{id: 0, contactName: "", telephoneNumber: ""}
]
}
})
useEffect(() => {
console.log("teste");
})
const handleChange = item => e => {
if (item === "contactName" || "telephone") {
// How can I set company.contact.contacts[<current_index>].contactName/telephoneNumber with the data typed?
} else {
setCompany({ ...company, [item]: e.target.value })
}
}
const handleClick = (e) => {
e.preventDefault();
if (e.target.value === "add") {
// How can I set company.contact.totalOfContact to 2 and create one more set of inputs tags for a second contact?
} else {
console.log(`The data of the company is: ${company}`);
}
}
return (
<div>
<form>
<h3>General Section</h3>
Name: <input type="text" onChange = {handleChange("name")} value = {company.name} />
<br />
City: <input type="text" onChange = {handleChange("city")} value = {company.city} />
<br />
<hr />
<h3>Contacts Section:</h3>
Name: <input type="text" onChange = {handleChange("contactName")} value = {company.contact.contacts[0].name} />
Telephone Numer: <input type="text" onChange = {handleChange("telephone")} value = {company.contact.contacts[0].telephoneNumber} />
<br />
<br />
<button value = "add" onClick = {(e) => handleClick(e)} >Add More Contact</button>
<br />
<br />
<hr />
<button value = "save" onClick = {(e) => handleClick(e)} >Save</button>
</form>
</div>
)
}
答案 0 :(得分:2)
为回答您的问题,让我们将这个问题的范围缩小到一个更简单的问题,即如何处理联系人数组。
您只需要了解以下内容:
我将使用TypeScript,以便您更好地理解。
const [state, setState] = React.useState<{
contacts: {name: string}[]
}>({contacts: []})
return (
<div>
{state.contacts.map((contact, index) => {
return (
<div>
Name:
<input value={contact.name} onChange={event => {
setState({
...state,
contacts: state.contacts.map((contact$, index$) =>
index === index$
? {...contact$, name: event.target.value}
: {...contact$}
)
})
}}/>
</div>
)
}}
</div>
)
此外,这种问题在React中相当普遍,因此了解并记住这种模式将对您有很大帮助。
答案 1 :(得分:2)
要更新状态值,可以使用functional setState
,
const handleChange = item => e => {
//Take the value in a variable for future use
const value = e.target.value;
if (item === "contactName" || "telephone") {
setCompany(prevState => ({
...prevState,
contact: {...prevState.contact, contacts: prevState.contact.contacts.map(c => ({...c, [item]: value}))}
}))
} else {
setCompany({ ...company, [item]: e.target.value })
}
}
要在单击按钮时添加新的输入集,您可以这样做,
const handleClick = (e) => {
e.preventDefault();
//This is new set of input to be added
const newSetOfInput = {id: company.contact.contacts.length, contactName: "", telephoneNumber: ""}
if (e.target.value === "add") {
// How can I set company.contact.totalOfContact to 2 and create one more set of inputs tags for a second contact?
setCompany(prevState => ({
...prevState,
contact: {...prevState.contact, contacts: prevState.contact.contacts.concat(newSetOfInput), totalOfContact: prevState.contact.contacts.length + 1}
}))
} else {
console.log(`The data of the company is: ${company}`);
}
}
最后,您需要遍历contacts
数组,如
{company.contact.contacts && company.contact.contacts.length > 0 && company.contact.contacts.map(contact => (
<div key={contact.id}>
Name: <input type="text" onChange = {handleChange("contactName")} value = {contact.contactName} />
<br/>
Telephone Numer: <input type="text" onChange = {handleChange("telephoneNumber")} value = {contact.telephoneNumber} />
</div>
))}
注意:您应该使用div
之类的块元素,而不要使用<br/>
答案 2 :(得分:1)
您可以执行以下操作。
import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";
const App = () => {
const [company, setCompany] = useState({
name: "",
city: "",
contact: {
totalOfContact: 1,
contacts: [{id: 0, contactName: "", telephoneNumber: ""}]
}
});
console.log(company);
useEffect(() => {
console.log("teste");
}, []);
const handleChange = (item, e,index) => {
if (item === "contactName" || item === "telephoneNumber") {
const contactsNew = [...company.contact.contacts];
contactsNew[index] = { ...contactsNew[index], [item]: e.target.value };
setCompany({
...company,
contact: { ...company.contact, contacts: contactsNew }
});
// How can I set company.contact.contacts[<current_index>].contactName/telephoneNumber with the data typed?
} else {
setCompany({ ...company, [item]: e.target.value });
}
};
const handleClick = e => {
e.preventDefault();
if (e.target.value === "add") {
const contactNew = {...company.contact};
contactNew.totalOfContact = contactNew.totalOfContact + 1;
contactNew.contacts.push({id:contactNew.totalOfContact -1, contactName: "", telephoneNumber: ""});
setCompany({...company, contact: {...contactNew}});
// How can I set company.contact.totalOfContact to 2 and create one more set of inputs tags for a second contact?
} else {
alert("Push company to somewhere to persist");
console.log(`The data of the company is: ${company}`);
}
};
return (
<div>
<form>
<h3>General Section</h3>
Name:{" "}
<input
type="text"
onChange={(e) => handleChange("name", e)}
value={company.name}
/>
<br />
City:{" "}
<input
type="text"
onChange={(e) => handleChange("city", e)}
value={company.city}
/>
<br />
<hr />
<h3>Contacts Section:</h3>
{company.contact.contacts.map((eachContact, index) => {
return <React.Fragment>
Name:{" "}
<input
type="text"
onChange={(e) => handleChange("contactName",e, index)}
value={eachContact.name}
/>
Telephone Numer:{" "}
<input
type="text"
onChange={(e) => handleChange("telephoneNumber",e, index)}
value={eachContact.telephoneNumber}
/>
<br />
</React.Fragment>
})}
<br />
<button value="add" onClick={e => handleClick(e)}>
Add More Contact
</button>
<br />
<br />
<hr />
<button value="save" onClick={e => handleClick(e)}>
Save
</button>
</form>
</div>
);
};
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
您的状态结构看起来像是useReducer钩子的理想选择。我建议您尝试使用代替useState的方法。我想,您的代码应该以这种方式看起来很可读。 https://reactjs.org/docs/hooks-reference.html#usereducer