在反应(奇怪的渲染)中从状态对象中删除项目

时间:2019-01-18 10:04:18

标签: reactjs rendering state

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

我已经尝试使用js控制台调试我的代码,但是由于控制台显示正确的状态,而组件“列表”呈现状态对象中不再存在的列表项,这使问题变得更加奇怪。 / p>

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;

据说我希望删除正确的列表项,但是即使状态对象说的不同,它仍然是最后一个不再渲染的项目。

1 个答案:

答案 0 :(得分:1)

主要问题是您将数组索引用作key。当您第一次呈现ListItems时:

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

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

  • ListItem名称= {'Tobi'}键= {0}
  • ListItem name = {'David'}键= {1}
  • ListItem name = {'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);