Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/474.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 从React中的数组中删除项时出现意外行为_Javascript_Reactjs - Fatal编程技术网

Javascript 从React中的数组中删除项时出现意外行为

Javascript 从React中的数组中删除项时出现意外行为,javascript,reactjs,Javascript,Reactjs,我到处寻找这个问题的答案,但我只需要一些人的帮助 我有一个简单的表单,用户可以在其中添加其他字段。用户还可以删除不再相关的字段 我对删除字段有意见 字段是从组件状态中的数组中呈现的,但是当我尝试从数组中删除某个项时,总是数组中最后一个被删除的项 import React, { Component } from "react"; class Form_newPriority extends Component { constructor(props) { super(props);

我到处寻找这个问题的答案,但我只需要一些人的帮助

我有一个简单的表单,用户可以在其中添加其他字段。用户还可以删除不再相关的字段

我对删除字段有意见

字段是从组件状态中的数组中呈现的,但是当我尝试从数组中删除某个项时,总是数组中最后一个被删除的项

import React, { Component } from "react";

class Form_newPriority extends Component {
  constructor(props) {
    super(props);
    this.state = {
      listName: "",
      rows: [{ id: 1, fieldValue: "" }],
    };
  }

  addrow = () => {
    const rows = [...this.state.rows];
    rows.push({
      id: rows.length + 1,
      fieldValue: "",
    });
    this.setState({ rows: rows });
  };

  removeRow = (idx) => {
    const rows = [...this.state.rows];
    rows.splice(idx, 1);
    this.setState({ rows: rows });
  };

  render() {
    return (
      <div>
        <input
          className="w-full bg-white border border-alice px-4 py-2 mb-1 h-12 rounded-lg"
          type="text"
        ></input>
        <h2>Items:</h2>
        {this.state.rows.map((row, idx) => {
          return (
            <React.Fragment>
              <input
                className="w-half bg-white border border-alice px-4 py-2 mb-4 mr-4  h-12 rounded-lg"
                key={idx}
                type="text"
                placeholder={idx}
              ></input>
              <button
                className="mb-4 text-red-700 inline-block"
                onClick={() => {
                  this.removeRow(idx);
                }}
              >
                Remove
              </button>
            </React.Fragment>
          );
        })}
        <button
          className="bg-alice hover:bg-gray-400 text-c_base text-sm font-bold py-1 px-2 rounded block mr-4"
          onClick={this.addrow}
        >
          Add row
        </button>
      </div>
    );
  }
}

export default Form_newPriority;

但结果是一样的


我对JS相当陌生,所以我在这里做了什么蠢事吗?

它可能会删除最后一个元素,因为您使用的是
索引
作为标识

当您使用递增
id
时,它更有意义

示例

const{Component,useState,useffect}=React;
类Form_newPriority扩展组件{
建造师(道具){
超级(道具);
此.state={
列表名:“”,
柜台:1,,
行:[{id:1,字段值:'}],
};
}
addrow=()=>{
const rows=[…this.state.rows];
常量计数器=this.state.counter+1;
推({
id:柜台,
字段值:“”,
});
this.setState({counter,rows});
};
移动路径=(idx)=>{
const rows=[…this.state.rows];
行拼接(idx,1);
this.setState({rows:rows});
};
render(){
返回(
项目:
{this.state.rows.map((row,idx)=>{
返回(
{
这是一种新的方法;
}}
>
去除
);
})}
添加行
);
}
}
ReactDOM.render(
,
document.getElementById('root'))
);

这是一个非常常见的问题,有时很难让人理解。它与react如何管理动态元素有关,比如从
映射返回时

问题 您可能已经看到一条警告,当从
map
返回时,应该使用。如果未给出
,react将自动使用数组元素的索引。这是问题的根源

React使用此
跟踪哪个元素是哪个元素。假设您有一个返回3个div的映射。React将用其
键标记每个div,以便知道将来需要更新的内容。结果如下:

<div key={0} val='a' />
<div key={1} val='b' />
<div key={2} val='c' />
也许你可以看看已经发生了什么?您删除了中间的元素,但为了做出反应,您删除了最后一个元素并更新了第二个元素。为什么?因为
基于索引,并且索引已更改。React将使用
2
键卸载
div
,并使用
1
键保持
div
。第二个
div
尚未删除,但已使用新道具重新渲染

解决方案 根级别的修复是,您需要为每个元素提供一个唯一的
,该键不会随时间变化。根据您的用例,这种方法的实现可能会有所不同

例如,如果您的列表保证每个条目都有一个唯一的值,则可以使用该值。这是最简单的解决方案,但并不总是可用的

我在过去使用过的一种解决方案是将计数器保持在每次添加元素时递增的状态。然后,我使用计数器为每个元素生成一个
id
。这样,如果删除了一个元素,
id
将不会更改

警告
人们在面对这个问题时常犯的一个错误是使用辅助函数为每个元素生成一个完全随机的
键。这可能会停止当前的问题,但这是一个非常糟糕的做法,可能会导致未来的错误。如果
更改每个渲染,元素将卸载并重新装载每个渲染。在类似这样的简单
div
示例中,这不会有任何副作用,但如果您的元素是另一个具有状态的组件,它将丢失其状态。如果您的元素是一个输入,它可能会在每次更新时失去焦点。这很诱人,但是不要对
键使用随机生成的数字

您为输入指定的值是映射元素的索引,您应该在状态中包含索引的值,并根据该索引删除元素,选中@Józef Podlecki answer,另外,在映射和返回渲染元素时,您应该使用
属性。您的示例显示的问题似乎与我遇到的问题相同。你能解释一下它是怎么工作的吗?这不是同一个问题。我使用
id
作为
@JózefPodlecki不,您使用的是
idx
,它是数组索引:
。如果你把它改成
,我想它会有用的。很抱歉,我没有跟上。如果您在示例中添加了3个输入,然后尝试删除第一个输入,那么将是最后一个删除的输入。我的错,更改了键。感谢您花时间解释这一点。我想我明白了。
<div key={0} val='a' />
<div key={1} val='b' />
<div key={2} val='c' />
<div key={0} val='a' />
<div key={1} val='c' />