如何在 React 中编辑多个输入控制的组件?
How do I edit multiple input controlled components in React?
我有一个组件将联系人对象存储为状态 - {firstName: "John", lastName: "Doe", phone: "1234567890} 我想创建一个表单来编辑此对象,但如果我希望输入保留原始接触参数的值,我需要使每个输入成为受控组件。但是,我不知道如何创建一个 handleChange 函数来调整每个参数,因为我state 仅保留 {contact: {...}}。以下是我目前拥有的 -
getInitialState: function () {
return ({contact: {}});
},
handleChange: function (event) {
this.setState({contact: event.target.value });
},
render: function () {
return (
<div>
<input type="text" onChange={this.handleChange} value={this.state.contact.firstName}/>
<input type="text" onChange={this.handleChange} value={this.state.contact.lastName}/>
<input type="text" onChange={this.handleChange} value={this.state.contact.lastName}/>
</div>
);
}
我希望在我的 handleChange 中我可以做类似
的事情
handleChange: function (event) {
this.setState({contact.firstName: event.target.value });
}
有两种方法可以更新嵌套对象的状态:
- 使用JSON.parse(JSON.stringify(object)) 创建对象的副本,然后更新副本并将其传递给setState。
- 使用immutability helpers in react-addons,这是推荐的方式。
您可以在此 JS Fiddle 中了解其工作原理。代码也在下面:
var Component = React.createClass({
getInitialState: function () {
return ({contact: {firstName: "first", lastName: "last", phone: "1244125"}});
},
handleChange: function (key,event) {
console.log(key,event.target.value);
//way 1
//var updatedContact = JSON.parse(JSON.stringify(this.state.contact));
//updatedContact[key] = event.target.value;
//way 2 (Recommended)
var updatedContact = React.addons.update(this.state.contact, {
[key] : {$set: event.target.value}
});
this.setState({contact: updatedContact});
},
render: function () {
return (
<div>
<input type="text" onChange={this.handleChange.bind(this,"firstName")} value={this.state.contact.firstName}/>
<input type="text" onChange={this.handleChange.bind(this,"lastName")} value={this.state.contact.lastName}/>
<input type="text" onChange={this.handleChange.bind(this,"phone")} value={this.state.contact.phone}/>
</div>
);
}
});
ReactDOM.render(
<Component />,
document.getElementById('container')
);
有一种 "simple" 方法可以做到这一点,还有一种 "smart" 方法。如果你问我,以聪明的方式做事并不总是最好的,因为以后可能更难共事。这样的话,两者都很好理解。
旁注:我想请您考虑的一件事是,您是否需要更新 contact
对象,或者您是否可以直接将 firstName
等保留在状态中?也许您在组件状态中有很多数据?如果是这种情况,将它分成职责范围更小的更小组件可能是个好主意。
"simple" 方式
changeFirstName: function (event) {
const contact = this.state.contact;
contact.firstName = event.target.value;
this.setState({ contact: contact });
},
changeLastName: function (event) {
const contact = this.state.contact;
contact.lastName = event.target.value;
this.setState({ contact: contact });
},
changePhone: function (event) {
const contact = this.state.contact;
contact.phone = event.target.value;
this.setState({ contact: contact });
},
render: function () {
return (
<div>
<input type="text" onChange={this.changeFirstName.bind(this)} value={this.state.contact.firstName}/>
<input type="text" onChange={this.changeLastName.bind(this)} value={this.state.contact.lastName}/>
<input type="text" onChange={this.changePhone.bind(this)} value={this.state.contact.phone}/>
</div>
);
}
"smart" 方式
handleChange: function (propertyName, event) {
const contact = this.state.contact;
contact[propertyName] = event.target.value;
this.setState({ contact: contact });
},
render: function () {
return (
<div>
<input type="text" onChange={this.handleChange.bind(this, 'firstName')} value={this.state.contact.firstName}/>
<input type="text" onChange={this.handleChange.bind(this, 'lastName')} value={this.state.contact.lastName}/>
<input type="text" onChange={this.handleChange.bind(this, 'phone')} value={this.state.contact.lastName}/>
</div>
);
}
更新:使用 ES2015+
的相同示例
本节包含与上面所示相同的示例,但使用了 ES2015+ 的功能。
要跨浏览器支持以下功能,您需要使用 Babel 转译您的代码,例如
预设 es2015 and react,
和插件 stage-0.
下面是更新的示例,使用 object destructuring 从状态中获取联系人,
spread operator 至
创建一个更新的联系人对象而不是改变现有的联系人对象,
通过 Classes 创建组件
扩展 React.Component,
并使用 arrow funtions 来
创建回调,这样我们就不必 bind(this)
.
"simple"方式,ES2015+
class ContactEdit extends React.Component {
changeFirstName = (event) => {
const { contact } = this.state;
const newContact = {
...contact,
firstName: event.target.value
};
this.setState({ contact: newContact });
}
changeLastName = (event) => {
const { contact } = this.state;
const newContact = {
...contact,
lastName: event.target.value
};
this.setState({ contact: newContact });
}
changePhone = (event) => {
const { contact } = this.state;
const newContact = {
...contact,
phone: event.target.value
};
this.setState({ contact: newContact });
}
render() {
return (
<div>
<input type="text" onChange={this.changeFirstName} value={this.state.contact.firstName}/>
<input type="text" onChange={this.changeLastName} value={this.state.contact.lastName}/>
<input type="text" onChange={this.changePhone} value={this.state.contact.phone}/>
</div>
);
}
}
"smart"方式,ES2015+
注意 handleChangeFor
是一个 curried function:
用 propertyName
调用它会创建一个回调函数,调用时会更新 [propertyName]
状态中的(新)联系人对象。
class ContactEdit extends React.Component {
handleChangeFor = (propertyName) => (event) => {
const { contact } = this.state;
const newContact = {
...contact,
[propertyName]: event.target.value
};
this.setState({ contact: newContact });
}
render() {
return (
<div>
<input type="text" onChange={this.handleChangeFor('firstName')} value={this.state.contact.firstName}/>
<input type="text" onChange={this.handleChangeFor('lastName')} value={this.state.contact.lastName}/>
<input type="text" onChange={this.handleChangeFor('phone')} value={this.state.contact.lastName}/>
</div>
);
}
}
ES6 一种线性方法
<input type="text"
value={this.state.username}
onChange={(e) => this.setState({ username: e.target.value })}
id="username"/>
这是通用的;
handleChange = (input) => (event) => {
this.setState({
...this.state,
[input]: event.target.value
});
}
然后像这样使用;
<input handleChange ={this.handleChange("phone")} value={this.state.phone}/>
handleChange(event){
this.setState({[event.target.name]:event.target.value});
this.setState({[event.target.name]:event.target.value});
}
最简洁的方法
这是我在我的简单应用程序中使用的一种方法。这是 React 中推荐的方法,它非常整洁。这与 ArneHugo 的回答非常接近,我也感谢 hm。这个想法是那个和反应形式网站的混合。
我们可以使用每个表单输入的 name 属性来获取特定的 propertyName 并根据它更新状态。这是我在 ES6 中用于上述示例的代码:
class ContactEdit extends React.Component {
handleChangeFor = (event) => {
const name = event.target.name;
const value = event.target.value;
const { contact } = this.state;
const newContact = {
...contact,
[name]: value
};
this.setState({ contact: newContact });
}
render() {
return (
<div>
<input type="text" name="firstName" onChange={this.handleChangeFor} />
<input type="text" name="lastName" onChange={this.handleChangeFor}/>
<input type="text" name="phone" onChange={this.handleChangeFor}/>
</div>
);
}
}
不同点:
- 我们不需要将状态分配为值属性。不需要值
- onChange 方法不需要在函数调用中有任何参数,因为我们使用名称属性来代替
- 我们在开始时声明每个输入的名称和值,并使用它们在代码中正确设置状态,我们使用 rackets 作为名称,因为它是一个属性。
我们这里的代码更少,并且可以通过非常聪明的方式从表单中获取任何类型的输入,因为 name 属性对于每个输入都有唯一的值。
请参阅我在 CodPen 中用于我的早期实验性博客应用程序的工作 example。
<input>
元素通常有一个 属性 名称。
我们可以从我们从事件处理程序接收到的事件对象访问这个名称 属性:
编写一个通用的更改处理程序
constructor () {
super();
this.state = {
name: '',
age: ''
};
this.handleChange = this.handleChange.bind(this);
}
handleChange (evt) {
this.setState({ [evt.target.name]: evt.target.value });
}
render () {
return (
<form>
<label>Name</label>
<input type="text" name="name" onChange={this.handleChange} />
<label>Age</label>
<input type="text" name="age" onChange={this.handleChange} />
</form>
);
}
source
updatePrevData=(event)=>{
let eventName=event.target.name;
this.setState({
...this.state,
prev_data:{
...this.state.prev_data,
[eventName]:event.target.value
}
})
console.log(this.state)
}
无需重复代码,简单易行
handleChange=(e)=>{
this.setState({
[e.target.id]:e.target.value
})
}
<Form.Control type="text" defaultValue={this.props.allClients.name} id="clientName" onChange={this.handleChange}></Form.Control>
<Form.Control type="email" defaultValue={this.props.allClients.email} id="clientEmail" onChange={this.handleChange}></Form.Control>
我有一个组件将联系人对象存储为状态 - {firstName: "John", lastName: "Doe", phone: "1234567890} 我想创建一个表单来编辑此对象,但如果我希望输入保留原始接触参数的值,我需要使每个输入成为受控组件。但是,我不知道如何创建一个 handleChange 函数来调整每个参数,因为我state 仅保留 {contact: {...}}。以下是我目前拥有的 -
getInitialState: function () {
return ({contact: {}});
},
handleChange: function (event) {
this.setState({contact: event.target.value });
},
render: function () {
return (
<div>
<input type="text" onChange={this.handleChange} value={this.state.contact.firstName}/>
<input type="text" onChange={this.handleChange} value={this.state.contact.lastName}/>
<input type="text" onChange={this.handleChange} value={this.state.contact.lastName}/>
</div>
);
}
我希望在我的 handleChange 中我可以做类似
的事情 handleChange: function (event) {
this.setState({contact.firstName: event.target.value });
}
有两种方法可以更新嵌套对象的状态:
- 使用JSON.parse(JSON.stringify(object)) 创建对象的副本,然后更新副本并将其传递给setState。
- 使用immutability helpers in react-addons,这是推荐的方式。
您可以在此 JS Fiddle 中了解其工作原理。代码也在下面:
var Component = React.createClass({
getInitialState: function () {
return ({contact: {firstName: "first", lastName: "last", phone: "1244125"}});
},
handleChange: function (key,event) {
console.log(key,event.target.value);
//way 1
//var updatedContact = JSON.parse(JSON.stringify(this.state.contact));
//updatedContact[key] = event.target.value;
//way 2 (Recommended)
var updatedContact = React.addons.update(this.state.contact, {
[key] : {$set: event.target.value}
});
this.setState({contact: updatedContact});
},
render: function () {
return (
<div>
<input type="text" onChange={this.handleChange.bind(this,"firstName")} value={this.state.contact.firstName}/>
<input type="text" onChange={this.handleChange.bind(this,"lastName")} value={this.state.contact.lastName}/>
<input type="text" onChange={this.handleChange.bind(this,"phone")} value={this.state.contact.phone}/>
</div>
);
}
});
ReactDOM.render(
<Component />,
document.getElementById('container')
);
有一种 "simple" 方法可以做到这一点,还有一种 "smart" 方法。如果你问我,以聪明的方式做事并不总是最好的,因为以后可能更难共事。这样的话,两者都很好理解。
旁注:我想请您考虑的一件事是,您是否需要更新 contact
对象,或者您是否可以直接将 firstName
等保留在状态中?也许您在组件状态中有很多数据?如果是这种情况,将它分成职责范围更小的更小组件可能是个好主意。
"simple" 方式
changeFirstName: function (event) {
const contact = this.state.contact;
contact.firstName = event.target.value;
this.setState({ contact: contact });
},
changeLastName: function (event) {
const contact = this.state.contact;
contact.lastName = event.target.value;
this.setState({ contact: contact });
},
changePhone: function (event) {
const contact = this.state.contact;
contact.phone = event.target.value;
this.setState({ contact: contact });
},
render: function () {
return (
<div>
<input type="text" onChange={this.changeFirstName.bind(this)} value={this.state.contact.firstName}/>
<input type="text" onChange={this.changeLastName.bind(this)} value={this.state.contact.lastName}/>
<input type="text" onChange={this.changePhone.bind(this)} value={this.state.contact.phone}/>
</div>
);
}
"smart" 方式
handleChange: function (propertyName, event) {
const contact = this.state.contact;
contact[propertyName] = event.target.value;
this.setState({ contact: contact });
},
render: function () {
return (
<div>
<input type="text" onChange={this.handleChange.bind(this, 'firstName')} value={this.state.contact.firstName}/>
<input type="text" onChange={this.handleChange.bind(this, 'lastName')} value={this.state.contact.lastName}/>
<input type="text" onChange={this.handleChange.bind(this, 'phone')} value={this.state.contact.lastName}/>
</div>
);
}
更新:使用 ES2015+
的相同示例本节包含与上面所示相同的示例,但使用了 ES2015+ 的功能。
要跨浏览器支持以下功能,您需要使用 Babel 转译您的代码,例如 预设 es2015 and react, 和插件 stage-0.
下面是更新的示例,使用 object destructuring 从状态中获取联系人,
spread operator 至
创建一个更新的联系人对象而不是改变现有的联系人对象,
通过 Classes 创建组件
扩展 React.Component,
并使用 arrow funtions 来
创建回调,这样我们就不必 bind(this)
.
"simple"方式,ES2015+
class ContactEdit extends React.Component {
changeFirstName = (event) => {
const { contact } = this.state;
const newContact = {
...contact,
firstName: event.target.value
};
this.setState({ contact: newContact });
}
changeLastName = (event) => {
const { contact } = this.state;
const newContact = {
...contact,
lastName: event.target.value
};
this.setState({ contact: newContact });
}
changePhone = (event) => {
const { contact } = this.state;
const newContact = {
...contact,
phone: event.target.value
};
this.setState({ contact: newContact });
}
render() {
return (
<div>
<input type="text" onChange={this.changeFirstName} value={this.state.contact.firstName}/>
<input type="text" onChange={this.changeLastName} value={this.state.contact.lastName}/>
<input type="text" onChange={this.changePhone} value={this.state.contact.phone}/>
</div>
);
}
}
"smart"方式,ES2015+
注意 handleChangeFor
是一个 curried function:
用 propertyName
调用它会创建一个回调函数,调用时会更新 [propertyName]
状态中的(新)联系人对象。
class ContactEdit extends React.Component {
handleChangeFor = (propertyName) => (event) => {
const { contact } = this.state;
const newContact = {
...contact,
[propertyName]: event.target.value
};
this.setState({ contact: newContact });
}
render() {
return (
<div>
<input type="text" onChange={this.handleChangeFor('firstName')} value={this.state.contact.firstName}/>
<input type="text" onChange={this.handleChangeFor('lastName')} value={this.state.contact.lastName}/>
<input type="text" onChange={this.handleChangeFor('phone')} value={this.state.contact.lastName}/>
</div>
);
}
}
ES6 一种线性方法
<input type="text"
value={this.state.username}
onChange={(e) => this.setState({ username: e.target.value })}
id="username"/>
这是通用的;
handleChange = (input) => (event) => {
this.setState({
...this.state,
[input]: event.target.value
});
}
然后像这样使用;
<input handleChange ={this.handleChange("phone")} value={this.state.phone}/>
handleChange(event){
this.setState({[event.target.name]:event.target.value});
this.setState({[event.target.name]:event.target.value});
}
最简洁的方法
这是我在我的简单应用程序中使用的一种方法。这是 React 中推荐的方法,它非常整洁。这与 ArneHugo 的回答非常接近,我也感谢 hm。这个想法是那个和反应形式网站的混合。 我们可以使用每个表单输入的 name 属性来获取特定的 propertyName 并根据它更新状态。这是我在 ES6 中用于上述示例的代码:
class ContactEdit extends React.Component {
handleChangeFor = (event) => {
const name = event.target.name;
const value = event.target.value;
const { contact } = this.state;
const newContact = {
...contact,
[name]: value
};
this.setState({ contact: newContact });
}
render() {
return (
<div>
<input type="text" name="firstName" onChange={this.handleChangeFor} />
<input type="text" name="lastName" onChange={this.handleChangeFor}/>
<input type="text" name="phone" onChange={this.handleChangeFor}/>
</div>
);
}
}
不同点:
- 我们不需要将状态分配为值属性。不需要值
- onChange 方法不需要在函数调用中有任何参数,因为我们使用名称属性来代替
- 我们在开始时声明每个输入的名称和值,并使用它们在代码中正确设置状态,我们使用 rackets 作为名称,因为它是一个属性。
我们这里的代码更少,并且可以通过非常聪明的方式从表单中获取任何类型的输入,因为 name 属性对于每个输入都有唯一的值。 请参阅我在 CodPen 中用于我的早期实验性博客应用程序的工作 example。
<input>
元素通常有一个 属性 名称。
我们可以从我们从事件处理程序接收到的事件对象访问这个名称 属性:
编写一个通用的更改处理程序
constructor () {
super();
this.state = {
name: '',
age: ''
};
this.handleChange = this.handleChange.bind(this);
}
handleChange (evt) {
this.setState({ [evt.target.name]: evt.target.value });
}
render () {
return (
<form>
<label>Name</label>
<input type="text" name="name" onChange={this.handleChange} />
<label>Age</label>
<input type="text" name="age" onChange={this.handleChange} />
</form>
);
}
source
updatePrevData=(event)=>{
let eventName=event.target.name;
this.setState({
...this.state,
prev_data:{
...this.state.prev_data,
[eventName]:event.target.value
}
})
console.log(this.state)
}
无需重复代码,简单易行
handleChange=(e)=>{
this.setState({
[e.target.id]:e.target.value
})
}
<Form.Control type="text" defaultValue={this.props.allClients.name} id="clientName" onChange={this.handleChange}></Form.Control>
<Form.Control type="email" defaultValue={this.props.allClients.email} id="clientEmail" onChange={this.handleChange}></Form.Control>