反应列表索引不正确

时间:2018-03-12 03:32:28

标签: javascript reactjs indexing

我通过制作一个简单的待办事项清单来学习React。到目前为止爱它。

当我删除待办事项时,它会删除单击要删除的列表项以上。我的索引必须关闭,但我无法找到原因。

没有奇怪的CSS去除每个项目的渲染删除按钮。索引似乎只是针对它上面的项目。

代码(缩短)

  handleSubmit(event) {
    let newTodos = this.state.todos;
    let index = newTodos.length;
    if (this.state.input !== "") {
      newTodos.unshift({
        text: this.state.input,
        key: this.state.input
      });
    }
    this.setState({todos: newTodos, input: ""});    
    event.preventDefault();
    this.setLocalStorage();
  }

  deleteItem(index) {
    let todoItems = this.state.todos;
    todoItems.splice(index, 1); 

    this.setState({
      todos: todoItems
    });
    this.setLocalStorage();
  }

  render() {
    return (
      <div className="todo-holder">
        <form className="todoInput-holder" onSubmit={this.handleSubmit}>
          <input type="text" placeholder="To do..." value={this.state.input} onChange={this.handleChange} />
        </form>
        <ul id="todo-list">
          <FlipMove duration={250} easing="ease-out"> 
          {
              this.state.todos.map(todos => {
                return <li key={todos.key} className="todo-li-item" >
                  <span className="todo-item">{todos.text}</span>
                  <span onClick={this.deleteItem} className="delet-todo">&#10005;</span>
                </li>;
              })
            } 
            </FlipMove>
        </ul>
      </div>
    );
  } 

思想?

4 个答案:

答案 0 :(得分:2)

原因实际上非常简单:onClick期望您传入参数为event的函数(请参阅ReactJS documentation)。因此,index deleteItem(index) event所期望的位置放置了splice个对象。 JavaScript在event调用中进行了秘密类型转换,因为event => event is an object => convert to valid Number is impossible => event becomes NaN => todos.splice(NaN, 1) => somehow splice treats NaN as 0 always不是数字,这导致您遇到的奇怪行为。

deleteItem

要解决此问题,您可以更改(index, event)event作为2个参数(实际上,如果您不打算使用bind,可以忽略它),并且您可以index MDN doctodos.map(el, index => { ... })(通过todos检索)从event到它,以绕过默认的class App extends React.Component { constructor(props) { super(props); this.state = { input: '', todos: [] } } handleSubmit = (event) => { let newTodos = this.state.todos; let index = newTodos.length; if (this.state.input !== "") { newTodos.unshift({ text: this.state.input, key: this.state.input }); } this.setState({todos: newTodos, input: ""}); event.preventDefault(); } deleteItem = (index, e) => { let todoItems = this.state.todos; todoItems.splice(index, 1); this.setState({ todos: todoItems // other answers complains about deep copy, but it is not the core issue here }); } handleChange = (e) => { this.setState({ input: e.target.value }) } render() { return ( <div className="todo-holder"> <form className="todoInput-holder" onSubmit={this.handleSubmit}> <input type="text" placeholder="To do..." value={this.state.input} onChange={this.handleChange} /> <button type="submit">submit</button> </form> <ul id="todo-list"> { this.state.todos.map((todos, i) => { // i is the index of current todo entry return <li key={todos.key} className="todo-li-item" > <span className="todo-item">{todos.text}</span> <span onClick={this.deleteItem.bind(this, i) /* this binds `i` to the first parameter of deleteItem(i, event) */} className="delet-todo">&#10005;</span> </li>; }) } </ul> </div> ); } } ReactDOM.render(<App />, document.getElementById('app'))参数。< / p>

以下代码是可运行的,我删除了localStorage代码以使其正常工作,如果需要,可以将其添加回来。

<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="app"></div>
float

答案 1 :(得分:1)

您实际上并未将索引传递给deleteItem方法。

首先,将索引传递给方法:

          this.state.todos.map((todos, index) => {
            return <li key={todos.key} className="todo-li-item" >
              <span className="todo-item">{todos.text}</span>
              <span onClick={() => this.deleteItem(index)} className="delet-todo">&#10005;</span>
            </li>;
          })

其次,不要使用splice等方法改变React的状态。 React状态中的任何内容都应该是不可变的,并且只能用setState触及。如果您要使用splice,请确保在数组的副本上执行此操作,例如

  deleteItem(index) {
    // .slice() will make a copy of the array
    let todoItems = this.state.todos.slice();
    todoItems.splice(index, 1); 

    this.setState({
      todos: todoItems
    });
    this.setLocalStorage();
  }

然而,更清晰的解决方案是使用Array的filter方法:

  deleteItem(index) {
    let todoItems = this.state.todos.filter((_, i) => i !== index)
    this.setState({
      todos: todoItems
    });
    this.setLocalStorage();
  }

或者,在React中使用您用于key的任何属性:

  this.state.todos.map((todos) => {
    return <li key={todos.key} className="todo-li-item" >
      <span className="todo-item">{todos.text}</span>
      <span onClick={() => this.deleteItem(todos.key)} className="delet-todo">&#10005;</span>
    </li>;
  })

  deleteItem(key) {
    let todoItems = this.state.todos.filter((todo) => todo.key !== key)
    this.setState({
      todos: todoItems
    });
    this.setLocalStorage();
  }

答案 2 :(得分:0)

这里有两个问题:

<span onClick={() => this.deleteItem(index)} className="delet-todo">&#10005;</span>

所以,基本上你需要改变你调用函数的方式到这样的

public class Adapter1 extends BaseAdapter {
private Context mContext;

// Keep all Images in array
public  Integer[] mThumbIds = {
        R.drawable.img1,
        R.drawable.img2,
        R.drawable.img3,
        R.drawable.img4,
        R.drawable.img5,
        R.drawable.img6,
        R.drawable.img7,
        R.drawable.img8,
        R.drawable.img9,
        R.drawable.img10,
        R.drawable.img11,
        R.drawable.img12,
        R.drawable.img13
};

希望它有所帮助!

答案 3 :(得分:0)

在render()方法中,不将索引传递给项目对象

this.state.todos.map((todos, index) => 
  <li key={todos.key} className="todo-li-item" >
    <span className="todo-item">{todos.text}</span>
    <span onClick={() => this.deleteItem(index)} className="delet-todo">&#10005;</span>
  </li>
);