Javascript 如何在 ReactJS 中实现带有受控组件的动态表单?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/42316604/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to implement a dynamic form with controlled components in ReactJS?
提问by Martin Shishkov
As I am looking at the examples in the reference for controlled form componentsin react.js official website, I am wondering how is one supposed to implement a formin which you would be able to removeand addinputelements dynamically in such a way that they are controlled components? Is this even possible?
当我在看controlled form componentsreact.js 官方网站参考中的例子时,我想知道应该如何实现一个form你可以动态地remove和addinput元素以这样的方式被控制的组件?这甚至可能吗?
In the examples we can see:
在示例中,我们可以看到:
class NameForm extends React.Component {
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
handleSubmit(event) {
alert('A name was submitted: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" value={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
Due to the nature of my work, I often find myself having to implement such forms. Moreover, I don't addor removeinputelements directly - I am managing custom components, but for the sake of simplicity here I am asking for basic form elements.
由于我的工作性质,我经常发现自己不得不实施这些表格。此外,我不直接使用add或removeinput元素 - 我正在管理自定义组件,但为了简单起见,我在这里要求基本的表单元素。
回答by Mayank Shukla
How adding/removing input elements dynamically possible?
如何动态添加/删除输入元素?
Yes, it is possible, you can add/remove inputelements dynamically, But for that you need to take care of few things:
是的,有可能,您可以添加/删除input元素dynamically,但为此您需要注意以下几点:
1-Proper binding of events.
1-正确绑定事件。
2-Array to store the values of each input element separately.
2-数组分别存储每个输入元素的值。
3-When user fill value in any input element then updating only that specific value in state.
3-当用户在任何输入元素中填充值时,仅更新状态中的该特定值。
Logic:
逻辑:
Maintain an array inside state, that will store the values. Use #array.mapto create ui (input element) for each array values. while creating the fields, use a remove buttonwith each field, and pass the index of field in that function, it will help you to identify which field you wants to delete, do the same thing for onChangealso.
在 state 内部维护一个数组,该数组将存储值。使用#array.map为每个数组值创建 ui(输入元素)。在创建字段时,button对每个字段使用删除,并在其中传递字段的索引function,它将帮助您确定要删除的字段,也做同样的事情onChange。
Check this example:
检查这个例子:
class App extends React.Component {
constructor(props) {
super(props);
this.state = { values: [] };
this.handleSubmit = this.handleSubmit.bind(this);
}
createUI(){
return this.state.values.map((el, i) =>
<div key={i}>
<input type="text" value={el||''} onChange={this.handleChange.bind(this, i)} />
<input type='button' value='remove' onClick={this.removeClick.bind(this, i)}/>
</div>
)
}
handleChange(i, event) {
let values = [...this.state.values];
values[i] = event.target.value;
this.setState({ values });
}
addClick(){
this.setState(prevState => ({ values: [...prevState.values, '']}))
}
removeClick(i){
let values = [...this.state.values];
values.splice(i,1);
this.setState({ values });
}
handleSubmit(event) {
alert('A name was submitted: ' + this.state.values.join(', '));
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
{this.createUI()}
<input type='button' value='add more' onClick={this.addClick.bind(this)}/>
<input type="submit" value="Submit" />
</form>
);
}
}
ReactDOM.render(<App />, document.getElementById('container'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id='container'/>
Check the working jsfiddle: https://jsfiddle.net/mayankshukla5031/ezdxg224/
检查工作jsfiddle:https: //jsfiddle.net/mayankshukla5031/ezdxg224/
回答by yuri
How adding/removing input elements dynamically with functional components?
如何使用功能组件动态添加/删除输入元素?
The same component from the selected answer reviewed and rewrited as a functional component.
所选答案中的相同组件被并重写为功能组件。
import React from 'react';
import { useState } from 'react';
function DynamicInput() {
const [values, setValues] = useState({ val: []});
function createInputs() {
return values.val.map((el, i) =>
<div key={i}>
<input type="text" value={el||''} onChange={handleChange.bind(i)} />
<input type='button' value='remove' onClick={removeClick.bind(i)} />
</div>
);
}
function handleChange(event) {
let vals = [...values.val];
vals[this] = event.target.value;
setValues({ val: vals });
}
const addClick = () => {
setValues({ val: [...values.val, '']})
}
const removeClick = () => {
let vals = [...values.val];
vals.splice(this,1);
setValues({ val: vals });
}
const handleSubmit = event => {
alert('A name was submitted: ' + values.val.join(', '));
event.preventDefault();
}
return (
<form onSubmit={handleSubmit}>
{createInputs()}
<input type='button' value='add more' onClick={addClick} />
<input type="submit" value="Submit" />
</form>
);
}
export default DynamicInput;
回答by rakwaht
You can easily use your state or the props that you are passing from other components to decide what your form should be.
您可以轻松地使用您从其他组件传递的状态或道具来决定您的表单应该是什么。
Here a dumb example:
这是一个愚蠢的例子:
class NameForm extends React.Component {
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
handleSubmit(event) {
alert('A name was submitted: ' + this.state.value);
event.preventDefault();
}
render() {
let myForm;
if(this.props.someprop == true){
myForm = (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" value={this.state.value} onChange= {this.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
else if(this.state.statevar == "expectedValue"){
myForm = (
// other HTML with embedded JS here
);
}
return (
{myForm}
);
}
}
I did it in the render method just to be clear but all the logic can be moved in auxiliary functions.
我在渲染方法中这样做只是为了清楚,但所有逻辑都可以在辅助函数中移动。
回答by Nandkishor Shinde
import React, { Component, } from 'react';
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
var childJson = []
export default class AddInvoice extends Component {
constructor(props) {
super(props);
this.state = {
Json: [],
rows: [{}]
}
}
handleChange = idx => e => {
const { name, value } = e.target;
const rows = [...this.state.rows];
rows[idx] = { [name]: value };
this.setState({ rows });
console.log(`rows-->>${this.state.rows[idx].amount}`);
childJson.push(this.dynamicJson(this.state.rows, idx))
this.setState({ Json: childJson })
};
handleAddRow = () => {
const item = {
name: "",
mobile: "",
btn: ""
};
this.setState({
rows: [...this.state.rows, item]
});
};
handleRemoveRow = (idx) => {
this.state.rows.splice(idx, 1);
this.setState({ rows: this.state.rows });
};
dynamicJson(rows, index) {
return {
"service": rows[index].text,
"tax": rows[index].tax,
"amount": rows[index].amount
}
};
render() {
return (
<div className="ui one column grid">
<div className=" row">
<div className="one wide computer one wide tablet one wide mobile column">
</div>
<div className="fourteen wide computer fourteen wide tablet fourteen wide mobile column">
<h1 id="title_header">INVOICE-ADD NEW</h1>
</div>
<div className="one wide computer one wide tablet one wide mobile column">
</div>
</div>
<div className=" row">
<div className="one wide computer one wide tablet one wide mobile column">
</div>
<div className="fourteen wide computer fourteen wide tablet fourteen wide mobile column">
<div id="#cus_segment" className="ui segment" style={{ backgroundColor: '#f5f5f5' }}>
<div className="ui form">
<div className="ui stackable grid">
<div className="six wide column">
<div className="field">
<label>Invoice No</label>
<input type="text" name="invoiceno" placeholder="Invoice No" value={this.state.invoiceno} onChange={e => this.setState({ invoiceno: e.target.value })} />
</div>
</div>
<div className=" six wide column">
<div className="field">
<label>Customer</label>
<select className="ui fluid selection search dropdown" name="customer" value={this.state.customer} onChange={e => this.setState({ customer: e.target.value })}>
<option defaultValue="">select</option>
<option value="[email protected]">[email protected]</option>
<option value="[email protected]">[email protected]</option>
<option value="[email protected]">[email protected]</option>
<option value="[email protected]">[email protected]</option>
</select>
</div>
</div>
<div className="one row">
<div className="six wide column">
<div className="field">
<label>Invoice Date</label>
<div className="ui calendar" id="calender1">
<div className="ui input right icon">
<i className="calendar icon"></i>
<input type="text" placeholder="Invoice Date" value={this.state.invoicedate} onBlur={e => this.setState({ invoicedate: e.target.value })} />
</div>
</div>
</div>
</div>
<div className="six wide column">
<div className="field">
<label>Due Date</label>
<div className="ui calendar" id="calender2">
<div className="ui input right icon">
<i className="calendar icon"></i>
<input type="text" placeholder="Due Date" value={this.state.duedate} onBlur={e => this.setState({ duedate: e.target.value })} />
</div>
</div>
</div>
</div>
</div>
<div className="two row">
<div className="six wide column">
<div className="field">
<label>Header</label>
<input type="text" name="header" placeholder="Header" value={this.state.header} onChange={e => this.setState({ header: e.target.value })} />
</div>
</div>
<div className="six wide column">
<div className="field">
<label>Remark</label>
<input type="text" name="remark" placeholder="Remark" value={this.state.remark} onChange={e => this.setState({ remark: e.target.value })} />
</div>
</div>
</div>
<div className="three row">
<div className="ten wide column">
<button className="ui primary button" type="submit">Save</button>
<button className="ui button" type="submit">Clear</button>
<button className="ui button" type="submit">Cancel</button>
</div>
</div>
<div className="foure row">
<div className="one wide column">
<div className="field">
<h4 style={{ textAlign: "center", borderRadius: 2 }}>Action</h4>
</div>
</div>
<div className="two wide column" style={{ marginLeft: 55 }}>
<div className="field">
<h4 style={{ textAlign: "center", borderRadius: 2 }}>Text</h4>
</div>
</div>
<div className="three column" style={{ marginLeft: 200 }}>
<div className="field">
<h4 style={{ textAlign: "center", borderRadius: 2 }}>Tax</h4>
</div>
</div>
<div className="foure wide column" style={{ marginLeft: 190 }}>
<div className="field">
<h4 style={{ textAlign: "center", borderRadius: 2 }}>Amount</h4>
</div>
</div>
</div>
{this.state.rows.map((item, idx) => (
<div className="five row" id="addr0" key={idx} >
<div className="one wide column">
<div className="field">
<div className="ui icon" style={{ backgroundColor: "#f76060", color: "white", height: 35, width: 40, textAlign: "center", borderRadius: 2 }} onClick={() => this.handleRemoveRow(idx)}>
<i className="trash alternate icon" style={{ marginTop: 8 }}></i>
</div>
</div>
</div>
<div className="five wide column">
<div className="field">
<input type="text" name="text" placeholder="text" value={this.state.rows[idx].text} onChange={this.handleChange(idx)} />
</div>
</div>
<div className="three wide column">
<div className="field">
<select className="ui fluid selection search dropdown " name="tax" id="tax_dropdown" value={this.state.rows[idx].tax} onChange={this.handleChange.bind(this)}>
<option defaultValue="">Select</option>
<option value="STAX">STAX</option>
<option value="VAT">VAT</option>
</select>
</div>
</div>
<div className="three wide column">
<div className="field">
<input type="text" name="amount" placeholder="amount" value={this.state.rows[idx].amount} onChange={this.handleChange(idx)} />
</div>
</div>
</div>
))}
<div className="six row">
<div className="two wide column">
<div className="field">
<div className="ui icon" style={{ backgroundColor: "#c4d3d3", height: 35, width: 55, textAlign: "center", borderRadius: 2 }} onClick={this.handleAddRow}>
<i className="plus icon" style={{ marginTop: 8 }}></i>
<label>Add</label>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div className="one wide computer one wide tablet one wide mobile column">
</div>
</div>
</div>
);
}
}
}

