删除输入组件时发生反应错误

时间:2017-09-28 20:24:19

标签: javascript reactjs

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

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 个答案:

答案 0 :(得分:2)

问题是您使用数组索引作为key,因此React将重用前两个li元素并删除最后一个元素。将key={index}更改为key={filter.id},它可以正常运行。

有关评论的更新&amp; downvote:假设该字段名为id,我假设实际代码中的过滤器具有唯一性。 CodePen似乎更像是一个精简版本来显示问题。但是如果你确实希望让每个按钮创建多个文本字段,那么你确实需要添加额外的东西以区分密钥(例如计数器)。这不会影响问题中所述的问题。

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

答案 1 :(得分:1)

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

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

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

答案 2 :(得分:0)

修改: 如果您的初始示例建议可以添加多个相同的元素,请避免使用您的ID作为其他答案建议的密钥,因为密钥需要是唯一的,这样他们可以(并且将会)重复!

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

如果要修改数组,则对象的键会发生变化,并且具有键的元素会被更改为&#39; 1&#39;在删除之后,以及之前有关键的组件&#39; 2&#39;成为一个有关键的&#39; 1&#39;等等。

React documentation建议不要使用索引作为关键字:
&#34;如果商品可以重新排序&#34;

,我们建议您不要使用键索引

为了避免这种情况,你应该使用某种独特的密钥生成,并将每个组件密钥存储在它自己的对象中,例如:

在构造函数中:

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语句现在完全没用。你试图用它做什么?