【问题标题】:Removing item from state object in react (strange rendering)在反应中从状态对象中删除项目(奇怪的渲染)
【发布时间】:2019-01-18 10:04:18
【问题描述】:

我在 Reactjs 中创建了一个项目,其中有一个我想在自定义列表中显示的名称列表。每个项目都有一个删除项目的按钮,但是每当我单击该按钮时,无论我单击哪个列表项,最后一个项目都会从列表中删除。

我已经尝试使用 js-console 调试我的代码,但这让问题变得更加奇怪,因为控制台显示正确的状态,而组件“List”呈现一个不再存在于状态对象中的列表项

import React, { Component } from 'react';
import './ListItem'
import ListItem from './ListItem';

class List extends Component {
    constructor(props) {
        super(props);
        this.state = {
            items: [
                {name: 'Tobi'},
                {name: 'Maxi'},
                {name: 'David'},
                {name: 'Peter'},
            ]
        }
    }

    removeItem = (id) => {
        let few = this.state.items;
        few.splice(id,1);
        //console.log(this.state.items);   
        this.setState({items: few}, function(){
            console.log(this.state.items.map((item) => item.name));
            this.forceUpdate();
        });
    }

    render() { 
        return (
            <div>
                <ul>
                    {this.state.items.map((item, i) => <ListItem name={item.name} key={i} id={i} remove={this.removeItem}/>)}
                </ul>
            </div>
        );
    }
}

import React, { Component } from 'react';

class ListItem extends Component {
    constructor(props) {
        super(props);
        this.state = {
            name: this.props.name,
            id: this.props.id
        }
    }

    test = () => {
        this.props.remove(this.state.id);
    }

    render() { 
        return (
            <li>{this.state.name} <button onClick={() => this.test()}>click me</button></li>
        );
    }
}

export default ListItem;

如前所述,我希望删除正确的列表项,但它始终是最后一个不再呈现的项目,即使状态对象表示不同。

【问题讨论】:

  • 这是一个有趣的问题。即使我看到类似的东西。可能是因为传递了密钥
  • 检查一下更改密钥。它有效,不确定这是否是预期的行为codesandbox.io/s/yq8k5ywwo1
  • 谢谢!这似乎按我的意图工作,但你能解释一下为什么它不能将索引作为 id 工作吗?
  • 那是因为密钥。如果键没有改变,则反应假定元素没有改变。键应该是对象的唯一值。那是 eslint 在将数组索引作为键时给出了错误。
  • 如果评论回答了你,请点赞。

标签: reactjs rendering state


【解决方案1】:

主要问题是您将数组索引用作key。当您第一次渲染您拥有的 ListItems 时:

  • ListItem 名称={'Tobi'} 键={0}
  • ListItem 名称={'Maxi'} 键={1}
  • ListItem 名称={'David'} 键={2}
  • ListItem 名称={'Peter'} 键={3}

假设您删除了索引为 1 的项目,所有其他项目将移动索引:

  • ListItem 名称={'Tobi'} 键={0}
  • ListItem 名称={'David'} 键={1}
  • ListItem 名称={'Peter'} 键={2}

React 只会比较键,因为第一次和第二次渲染的唯一区别是 key={3} 的项目不存在,这是将从 dom 中删除的项目。

还要避免直接改变状态(few.splice(id,1)),尽量避免this.forceUpdate()

尝试在您的数据中使用实际的 id:

import React, { Component } from "react";
import ReactDOM from "react-dom";

import "./styles.css";

class List extends Component {
  constructor(props) {
    super(props);
    this.state = {
      items: [
        { id: 1, name: "Tobi" },
        { id: 2, name: "Maxi" },
        { id: 3, name: "David" },
        { id: 4, name: "Peter" }
      ]
    };
  }

  removeItem = id => {
    let few = this.state.items.filter(item => item.id !==id);
    //console.log(this.state.items);
    this.setState({ items: few }, function() {
      console.log(this.state.items.map(item => item.name));
      //this.forceUpdate();
    });
  };

  render() {
    return (
      <div>
        <ul>
          {this.state.items.map((item, i) => (
            <ListItem
              name={item.name}
              key={item.id}
              id={item.id}
              remove={this.removeItem}
            />
          ))}
        </ul>
      </div>
    );
  }
}

class ListItem extends Component {
  constructor(props) {
    super(props);
    this.state = {
      name: this.props.name,
      id: this.props.id
    };
  }

  test = () => {
    this.props.remove(this.state.id);
  };

  render() {
    return (
      <li>
        {this.state.name} <button onClick={() => this.test()}>click me</button>
      </li>
    );
  }
}


function App() {
  return (
    <div className="App">
      <List />
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-23
    • 2019-10-27
    • 1970-01-01
    • 1970-01-01
    • 2017-02-22
    • 1970-01-01
    相关资源
    最近更新 更多