[英]How to get react to correctly render a list of removable inputs?
I'm trying to render a list of inputs in react and bind the input values to an array. 我正在尝试在react中呈现输入列表并将输入值绑定到数组。 I'm also trying to make it so the list items are removable.
我也试图这样做,所以列表项是可移动的。 However, when I remove an item from the array, the input items are not updated how I would expect.
但是,当我从数组中删除一个项目时,输入项目不会更新我的期望。 Instead of removing the input that was removed from the middle of the array, the last input is removed and the middle input remains.
不是删除从数组中间删除的输入,而是删除最后一个输入并保留中间输入。
var Inputs = React.createClass({
getInitialState: function() {
return {
inputarr: ['']
};
},
render: function() {
var self = this;
return <div>{ this.state.inputarr.map(function (value, i) {
return <div key={i}><input onChange={function (e) {self.onChangeInput(i, e)}}/>
{ i < (self.state.inputarr.length - 1) && <button onClick={function () {self.onRemove(i)}}>x</button>}
</div>;
}) }</div>;
},
onChangeInput: function (i, e) {
this.state.inputarr[i] = e.target.value;
if (this.state.inputarr[this.state.inputarr.length - 1] !== '') {
this.state.inputarr.push('');
}
this.setState({
inputarr: this.state.inputarr.slice(0)
});
},
onRemove: function (i) {
this.state.inputarr.splice(i, 1);
this.setState({
inputarr: this.state.inputarr.slice(0)
});
}
});
ReactDOM.render(
<Inputs/>,
document.getElementById('container')
);
You can run this in this fiddle: https://jsfiddle.net/vvd7hex9/1/ 你可以在这个小提琴中运行: https : //jsfiddle.net/vvd7hex9/1/
The last input is removed. 最后一个输入被删除。
The middle input to be removed and only 2 inputs should contain the contents in the inputarr
array. 要删除的中间输入,只有2个输入应包含
inputarr
数组中的内容。
Why does this happen? 为什么会这样? How can I fix it to remove the correct input?
如何修复它以删除正确的输入?
Ahhhh, this is a classic javascript problem. 啊,这是一个经典的JavaScript问题。 It has to do with your
map
statement. 它与你的
map
语句有关。 You can read more about the specific details here , but what it boils down to is that when the click events actually fire, the value of i
is equal to inputarr.length - 1
. 您可以在这里阅读有关具体细节的更多信息,但它归结为当点击事件实际触发时,
i
的值等于inputarr.length - 1
。 To fix this, you need some way of preserving the value of i
during each loop. 要解决这个问题,你需要一些在每个循环中保留
i
值的方法。 The easiest way to do this is to change the click event to this: 最简单的方法是将click事件更改为:
<button onClick={self.onRemove(i)}>x</button>
and change onRemove
to this: 并改变
onRemove
to this:
onRemove: function (i) {
var self = this;
return function(e) {
self.state.inputarr.splice(i, 1);
self.setState({
inputarr: this.state.inputarr.slice(0)
});
}
}
Some more info about closures can be found here if you're unfamiliar 如果你不熟悉,可以在这里找到关于闭包的更多信息
I think it would be better to have separate Input component and App component. 我认为最好有单独的Input组件和App组件。 Then you can create increment and decrement methods and pass them down from App to your Input components.
然后,您可以创建递增和递减方法,并将它们从App传递到Input组件。 I have build a little pen to show how you can achieve it.
我已经制作了一支笔来展示你如何实现它。
I used some useful methods from lodash so take a look how them work. 我使用了lodash的一些有用的方法,所以看看它们是如何工作的。
https://codepen.io/dagman/pen/oYaYyL https://codepen.io/dagman/pen/oYaYyL
The code itself. 代码本身。
class App extends React.Component {
constructor(props) {
super(props);
this.increment = this.increment.bind(this);
this.decrement = this.decrement.bind(this);
this.state = {
quantity: [0],
};
}
increment(value) {
const { quantity } = this.state;
this.setState({
quantity: quantity.concat(_.last(quantity) + 1),
});
}
decrement(el) {
const { quantity } = this.state;
this.setState({ quantity: _.without(quantity, el) })
}
render() {
const inputs = this.state.quantity.map(x => (
<Input
increment={this.increment}
decrement={this.decrement}
key={x}
toDelete={x}
/>
));
return (
<form>
{inputs}
</form>
);
}
}
class Input extends React.Component {
constructor(props) {
super(props);
this.onChange = this.onChange.bind(this);
this.onBtnClick = this.onBtnClick.bind(this);
this.state = {
value: '',
shouldIncrementQuantity: true,
};
}
onChange(e) {
const value = e.target.value;
this.setState({ value });
if(value.trim().length > 0 && this.state.shouldIncrementQuantity) {
this.setState({
shouldIncrementQuantity: false,
}, () => this.props.increment());
}
}
onBtnClick(e) {
e.preventDefault();
this.props.decrement(this.props.toDelete);
}
render() {
return (
<p className="input-field">
<input
type="text"
value={this.state.value}
onChange={this.onChange}
/>
<button onClick={this.onBtnClick}>x</button>
</p>
);
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.