[英]Updating React state with Hooks and tags
我对如何在 2 种情况下使用钩子更新 React state 有语法疑问。
1)我有一个名为公司的 state 和一个填写它的表格。 在联系部分,有两个输入是指公司员工(姓名和电话号码)。 但是,如果公司有多个要联系的员工,则有一个“添加更多联系人”按钮,该按钮必须复制相同的输入(当然,针对第二个联系人)。 我怎样才能做到这一点? 我的意思是,要在 state 内的数组“联系人”中生成另一个索引,增加具有该数组的 object 内的 totalOfContacts 并创建输入标签,以便用户可以键入第二个联系人的数据?
2)当我输入任何输入时,代码会触发 handleChange function。 “名称”和“城市”已经更新了 state,因为它们是简单的状态。 但是我如何更新联系人姓名和他的电话号码,因为它们是 state 内数组索引的一部分?
下面的代码已经在运行,我的 2 个问题正是注释的两行(第 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>
)
}
为了回答你的问题,让我们把这个问题简化为一个更简单的问题,即如何处理联系人数组。
你只需要知道以下几点:
我将使用 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 中相当普遍,因此理解和记住这种模式会对你有很大帮助。
要更新 state 值,您可以使用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/>
你可以做这样的事情。
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);
您的 state 结构看起来是 useReducer 挂钩的理想候选者。 我建议你试试这个,而不是 useState。 我想你的代码应该看起来很可读。 https://reactjs.org/docs/hooks-reference.html#usereducer
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.