简体   繁体   English

如何做出反应以正确呈现可移动输入列表?

[英]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/

What happens? 怎么了?

  1. add something to the first input, a second will appear. 在第一个输入中添加内容,将出现第二个输入。 Type in 3 different inputs. 输入3个不同的输入。
  2. remove the second input using the x button. 使用x按钮删除第二个输入。

The last input is removed. 最后一个输入被删除。

What I expected to happen 我期望发生什么

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM