反应从表中删除特定行

时间:2019-05-24 07:02:04

标签: javascript arrays reactjs

我有一个表部件。 该表的每一行也是组成部分。

    class FormulaBuilder extends Component {
        constructor(props) {
            super(props);
            this.state = {
                rows: [{}]
            }
        }
handleAddRow = () => {
        const item = {};

        this.setState({
            rows: [...this.state.rows, item]
        });
    };

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

     render() {
            return (
               {
                   this.state.rows.map((item, idx) => {
                        return (
                           <React.Fragment key={idx}>
                                 <ConcoctionRow
                                  removeSpecificRow={(idx) =>this.handleRemoveSpecificRow(idx)}
                                  id={idx} />
                            </React.Fragment>);
                })
             });
            }
    }

在子组件中有一个按钮。单击后,将调用父组件中的事件:

class ConcoctionRow extends Component {
    constructor(props) {
        super(props);
    }

  handleRemoveSpecificRow = () => {
        this.props.removeSpecificRow(this.props.id);
    }
}

这些属性传递了数组的索引。但是只有最后一行总是被删除而不是特定的。

我的坏处在哪里?附言我是JS新手。

2 个答案:

答案 0 :(得分:2)

几件事,您要避免使用.splice()更新组件中的数组。通常,这实际上最终会改变您的原始状态,而不是创建一个新状态。直接违反了React概念。

同样,让我们​​在控制台上尝试一些操作:

const arr = [1, 2, 3] <-- this is your state
const newArr = arr  <-- you created a reference of your state. This does not actually create a new copy.

现在,如果您拼接newArr

newArr.splice(0, 1) <-- now newArr = [2, 3]

好吧,你还改变了原始状态。

arr <-- is now also [2, 3]

JavaScript中常见的误解是,当您创建一个等于现有变量的新变量时,您期望它实际上会创建一个新副本。

let cat = {id: 1, name: "bunny"}
let myCat = cat

实际上并非如此,您的新变量不是显式创建新副本,而是指向派生自其的原始对象的相同引用。如果我做了类似的事情:

myCat.age = 2  <-- Now myCat has a new property of age.
myCat <-- {id: 2, name: "bunny", age: 2}

但是,因为这两个变量指向相同的引用。您还可以对原始猫对象进行变异

cat <-- {id: 2, name: "bunny", age: 2}

使用array.filter()来创建一个全新的数组。

以下是您的代码示例以及供参考的沙箱:https://codesandbox.io/s/heuristic-nobel-6ece5

import React from "react";
import ConcoctionRow from "./ConcoctionRow";

class FormulaBuilder extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      rows: [{}, {}, {}]
    };
  }
  handleAddRow = () => {
    const item = {};

    this.setState({
      rows: [...this.state.rows, item]
    });
  };

  handleRemoveSpecificRow = idx => {
    const { rows } = this.state;

    const updatedRows = rows.filter((row, index) => {
      return index !== idx;
    });

    this.setState({
      rows: updatedRows
    });
  };
  render() {
    return (
      <div>
        {this.state.rows.map((item, idx) => {
          return (
            <React.Fragment key={idx}>
              <ConcoctionRow
                removeSpecificRow={this.handleRemoveSpecificRow}
                id={idx}
              />
            </React.Fragment>
          );
        })}
      </div>
    );
  }
}

export default FormulaBuilder;

答案 1 :(得分:0)

我显示了在这种情况下要使用的模式。我建议对项目使用id而不是数组索引。 filter数组函数是不可变的(它会创建一个新数组,而不会使前一个数组发生变化),因此可以在设置状态下使用。 setState的功能形式也不错。

const Row = ({ onClick, children, id }) => (
  <li>{children} <button onClick={() => onClick(id)}>Delete</button></li>
)

class App extends React.Component {
  state = {
    list: [
      {id: 1, label: 'foo' },
      {id: 2, label: 'bar' }
    ]
  }
  
  handleDelete = id => {
    this.setState(prevState => ({
      list: prevState.list.filter(row => (
        row.id !== id
      ))
    }))
  }
  
  render(){
    const { list } = this.state;
    
    return (
      <ul>
        {list.map(({ id, label }) => (
          <Row id={id} onClick={this.handleDelete}>{label}</Row>
        ))}
      </ul>
    )
  }
}

ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>