删除输入组件时react错误

IT技术 javascript reactjs
2021-05-24 19:16:14

我不确定这是否是react问题,但我在这个问题上挣扎了很多。我试图创建一个简单的例子来发布我的项目:

https://codepen.io/as3script/pen/VMbNdz?editors=1111

示例中有四个按钮。

要重现该问题,请按前三个按钮中的每一个以创建文本输入并输入值。例如,在第一个中输入 100,在第二个中输入 200,在第三个中输入 300。现在按第四个按钮删除第一个输入。

它应该保留第二个和第三个各自的值,200 和 300,但它在第二个中显示 100,在第三个中显示 200。


此代码与 CodePen 上的代码相同,只是不允许在没有此代码的情况下发布链接。

class ButtonComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {filtersArr:[]}
    this.addButtons = this.addButtons.bind(this);
    this.removeButtons = this.removeButtons.bind(this);
    this.getInput = this.getInput.bind(this);
    this.onChangeHandler = this.onChangeHandler.bind(this);
  }

   addButtons(e){     
    let tempArr = this.state.filtersArr;

    tempArr.push({comp:this.getInput(e.target.id), id:e.target.id});

    this.setState({filtersArr:tempArr});
  }

  removeButtons(e){
    console.log(e.target.id);
    let newArr = this.state.filtersArr.filter((filter)=>{
      return (filter.id !=='FirstButton')
    })
    this.setState({filtersArr:newArr});
  }

  onChangeHandler(e){
    console.log(e.target.value);
  }

  getInput(id){
    return (
      <div>
        <h6>{id}</h6>
        <input
          id="min"
          type="text"
          placeholder="min"
          onChange={this.onChangeHandler}/>
      </div>
    )
  }

  render() {
    let styles = {
      display:'inline-block'
    }

    return (
      <div>
        <p>Add three buttons and enter the number in each input, and remove amt.</p>
        <button id="FirstButton" onClick={this.addButtons}>FirstButton</button>
        <button id="SecondButton" onClick={this.addButtons}>SecondButton</button>
        <button id="ThirdButton" onClick={this.addButtons}>ThirdButton</button>

        <button id="FirstButton" onClick={this.removeButtons}>Remove firstButton</button>

          <ul>
            {this.state.filtersArr.map((filter, index)=>{
              return <li style={styles} key={index}>{filter.comp}</li>
            })
            }
          </ul>
      </div>
    );
  }
}

ReactDOM.render(
  <ButtonComponent/>,
  document.getElementById('root')
);
3个回答

问题是您使用数组索引作为您的key,因此 React 将重用前两个li元素并删除最后一个。更改key={index}key={filter.id},它会按您的预期工作。

关于评论和反对票的更新:我假设实际代码中过滤器的唯一性,因为该字段被称为idCodePen 似乎更像是一个精简版来显示问题。但是如果您确实希望让每个按钮创建多个文本字段,您确实需要添加一些额外的东西来区分键(例如计数器)。不过,这不会影响问题中所述的问题。

再次查看代码,我注意到getInput将是提取到单独(无状态)组件中的理想候选者,例如FilterInput. 这比将子渲染保持在组件状态更适合react模型。

该代码在 div 中生成 3 个文本框。这些文本框通过输入数字(100、200、300)来更新。当您单击 RemoveFirstButton 时,存储这些组件的状态会更新并调用渲染。

渲染函数对当前状态和前一状态进行 diff 并删除最后一个 div,其中包含数字 300。这是因为,对于渲染函数,数组的第一个元素从 FirstButton 更改为 SecondButton,即第二个元素从 SecondButton 更改为 ThirdButton 并且第三个元素不再存在。

为了让它按预期工作,您需要将元素的键从数组的索引更改为元素的 id,以便 render 方法可以区分元素之间的差异。

编辑:请避免使用您的 id 作为键,因为其他答案建议是否可以添加多个相同的元素,因为键需要是唯一的,这样它们就可以(并且将会)重复!


您的问题在于您错误地使用了关键属性。React 期望您的组件具有常量键,因此它可以决定何时以及哪些需要更新。

如果您正在修改数组,则对象的键正在更改,并且删除之前具有键 '1' 的元素随后消失,之前具有键 '2' 的组件变为具有键 '1' 的组件,并且等等。

阵营文档建议不要使用索引的关键,以及:
“我们不建议使用索引键,如果项目可以重新排列”

为避免这种情况,您应该使用某种唯一键生成并将每个组件键存储在它自己的对象中,例如:

在构造函数中:

this.nextKey = 0

添加新组件时:

tempArr.push({comp: comp, id: e.target.id, key: this.nextKey++});

在渲染函数中:

return <li style={styles} key={filter.key}>{filter.comp}</li>

我修改了您的示例以包含这些行,您可以在这里找到它:https : //codepen.io/Isti115/pen/MEmMZP?editors=1111


此外,还有一些其他提示:


ps.:你使用的switch语句现在完全没用。你试图用它完成什么?