简体   繁体   中英

React table from data remove row not refresh

I have a table, rendered from this data.

{
  key: 1,
  model: "11111111",
  sn: "TERR5RRTR555465",
  fv: "FV/12344/2019"
},
{
  key: 2,
  model: "2222222",
  sn: "TERR5RRTR555465",
  fv: "FV/12344/2019"
},
{
  key: 3,
  model: "33333", 
  sn: "TERR5RRTR555465",
  fv: "FV/12344/2019"
},
{
  key: 4,
  model: "44444444",
  sn: "TERR5RRTR555465",
  fv: "FV/12344/2019"
}

Rows have button to remove row from table. After double click, row is removed from data, but on page is removed only last row from table. And if I remove another one random row, on page is remove always last row table.

Where is problem and what I don't understand in REACT?

My REACT example:

https://codesandbox.io/embed/react-table-array-99xiq

and code:

import React from "react";

import { Button, Form, Input, Message, Table } from "semantic-ui-react";
import "./styles.css";
import "semantic-ui-css/semantic.min.css";

export default class App extends React.Component {
  constructor() {
    super();
    this.state = {
      lista: [
        {
          key: 1,
          model: "11111111",
          sn: "TERR5RRTR555465",
          fv: "FV/12344/2019"
        },
        {
          key: 2,
          model: "2222222",
          sn: "TERR5RRTR555465",
          fv: "FV/12344/2019"
        },
        { key: 3, model: "33333", sn: "TERR5RRTR555465", fv: "FV/12344/2019" },
        {
          key: 4,
          model: "44444444",
          sn: "TERR5RRTR555465",
          fv: "FV/12344/2019"
        },
        { key: 5, model: "5555555", sn: "TERR5RRTR555465", fv: "FV/12344/2019" }
      ]
    };
    this.toDoChangeValues = this.toDoChangeValues.bind(this);
    this.removeListIndex = this.removeListIndex.bind(this);
  }

  toDoChangeValues(n, v) {
    var nam = n.split("_");
    var list = this.state.lista;
    var indx = list.findIndex(x => x.key == nam[1]);
    list[indx][nam[0]] = v;
    this.setState({ lista: list });
  }

  removeListIndex(n) {
    this.setState(prevState => ({
      lista: prevState.lista.filter(row => row.key != n)
    }));
  }

  render() {
    if (
      this.state.lista.find(function(x) {
        return x.model === "" && x.sn === "" && x.fv === "";
      }) === undefined
    ) {
      var new_id = Math.max.apply(null, [
        ...this.state.lista.map(function(o) {
          return o.key;
        }),
        0
      ]);
      this.setState({
        lista: [
          ...this.state.lista,
          { key: new_id + 1, model: "", sn: "", fv: "" }
        ]
      });
    }
    const { lista } = this.state;
    return (
      <>
        <div className="segm_space">
          <Message attached header="Table list" />
          <Form className="attached fluid segment">
            <Table
              basic="very"
              celled
              compact
              className="list_hardwares"
              unstackable
            >
              <Table.Header>
                <Table.Row>
                  <Table.HeaderCell>Data</Table.HeaderCell>
                  <Table.HeaderCell>Number</Table.HeaderCell>
                  <Table.HeaderCell>Type</Table.HeaderCell>
                  <Table.HeaderCell style={{ width: "1%" }} />
                </Table.Row>
              </Table.Header>

              <Table.Body>
                {lista.map(
                  function(object) {
                    return (
                      <RowData
                        obj={object}
                        rmveIndx={this.removeListIndex}
                        chVal={this.toDoChangeValues}
                      />
                    );
                  }.bind(this)
                )}
              </Table.Body>
            </Table>
          </Form>
        </div>
      </>
    );
  }
}

export class RowData extends React.Component {
  constructor() {
    super();
    this.state = {
      trash: false
    };
    this.onTodoChange = this.onTodoChange.bind(this);
    this.onTrash = this.onTrash.bind(this);
  }

  onTodoChange(e) {
    const { name, value } = e.target;
    this.props.chVal(name, value);
  }

  onTrash(e) {
    if (!this.state.trash) {
      this.setState({ trash: true }, () => {
        setTimeout(
          function() {
            this.setState({ trash: false });
          }.bind(this),
          2000
        );
      });
    } else {
      this.props.rmveIndx(e.target.name || e.target.closest("button").name);
    }
  }

  render() {
    return (
      <Table.Row id={"id_" + this.props.obj.key}>
        <Table.Cell>
          <Input
            fluid
            transparent
            onChange={this.onTodoChange}
            name={"model_" + this.props.obj.key}
            placeholder="00000000000"
            defaultValue={this.props.obj.model}
          />
        </Table.Cell>
        <Table.Cell>
          <Input
            fluid
            transparent
            onChange={this.onTodoChange}
            name={"sn_" + this.props.obj.key}
            placeholder="XXXXXXXXXXXXXXX"
            defaultValue={this.props.obj.sn}
          />
        </Table.Cell>
        <Table.Cell>
          <Input
            fluid
            transparent
            onChange={this.onTodoChange}
            defaultValue={this.props.obj.fv}
          />
        </Table.Cell>
        <Table.Cell>
          <Button
            name={this.props.obj.key}
            onClick={this.onTrash}
            color={this.state.trash ? "blue" : undefined}
            compact
            size="tiny"
            icon="trash"
          />
        </Table.Cell>
      </Table.Row>
    );
  }
}
import React from "react";

import { Button, Form, Input, Message, Table } from "semantic-ui-react";
import "./styles.css";
import "semantic-ui-css/semantic.min.css";

export default class App extends React.Component {
  constructor() {
    super();
    this.state = {
      inputFocus: null,
      lista: [
        {
          key: 1,
          model: "11111111",
          sn: "TERR5RRTR555465",
          fv: "FV/12344/2019"
        },
        {
          key: 2,
          model: "2222222",
          sn: "TERR5RRTR555465",
          fv: "FV/12344/2019"
        },
        { key: 3, model: "33333", sn: "TERR5RRTR555465", fv: "FV/12344/2019" },
        {
          key: 4,
          model: "44444444",
          sn: "TERR5RRTR555465",
          fv: "FV/12344/2019"
        },
        { key: 5, model: "5555555", sn: "TERR5RRTR555465", fv: "FV/12344/2019" }
      ]
    };
  }

  handleChange = (value,name,id) => {
    const {lista} = this.state;
    const newData = [...lista.filter(item => item.key !== id), { ...lista.filter(item => item.key === id)[0], [name]: value}];
    this.setState({lista: newData});
  }

  addData = () => {
    const {lista} = this.state;
    this.setState({ lista: [...lista, { key: lista[lista.length - 1].key + 1, model: this.model.inputRef.current.value, sn: this.sn.inputRef.current.value, fv: this.fv.inputRef.current.value}]});
    this.model.inputRef.current.value = '';
    this.sn.inputRef.current.value = '';
    this.fv.inputRef.current.value = '';
  }

  trash = (id) => {
    this.setState({lista: this.state.lista.filter(item => item.key !== id)});
  }

  render() {
    const { lista } = this.state;
    return (
      <>
        <div className="segm_space">
          <Message attached header="Table list" />
          <Form className="attached fluid segment">
            <Table
              basic="very"
              celled
              compact
              className="list_hardwares"
              unstackable
            >
              <Table.Header>
                <Table.Row>
                  <Table.HeaderCell>Data</Table.HeaderCell>
                  <Table.HeaderCell>Number</Table.HeaderCell>
                  <Table.HeaderCell>Type</Table.HeaderCell>
                  <Table.HeaderCell style={{ width: "1%" }} />
                </Table.Row>
              </Table.Header>

              <Table.Body>
                {lista.sort((prev,next) => {
                  if (prev.key > next.key) return 1;
                  return -1;
                }).map(item => <Table.Row key={item.key}>
                  <Table.Cell>
                    <Input
                      fluid
                      transparent
                      name='model'
                      onChange={(e,data) => this.handleChange(data.value,data.name, item.key)}
                      placeholder="00000000000"
                      defaultValue={item.model}
                    />
                  </Table.Cell>
                  <Table.Cell>
                    <Input
                      fluid
                      transparent
                      name='sn'
                      onChange={(e, data) => this.handleChange(data.value, data.name, item.key)}
                      placeholder="XXXXXXXXXXXXXXX"
                      defaultValue={item.sn}
                    />
                  </Table.Cell>
                  <Table.Cell>
                    <Input
                      fluid
                      transparent
                      name='fv'
                      onChange={(e, data) => this.handleChange(data.value, data.name, item.key)}
                      defaultValue={item.fv}
                    />
                  </Table.Cell>
                  <Table.Cell>
                    <Button
                      onClick={() => this.trash(item.key)}
                      compact
                      size="tiny"
                      icon="trash"
                    />
                  </Table.Cell>
                </Table.Row>)}
                <Table.Row>
                  <Table.Cell>
                    <Input
                      fluid
                      transparent
                      name='model'
                      ref={n => this.model = n}
                      placeholder="00000000000"
                    />
                  </Table.Cell>
                  <Table.Cell>
                    <Input
                      fluid
                      transparent
                      name='sn'
                      ref={n => this.sn = n}
                      placeholder="XXXXXXXXXXXXXXX"
                    />
                  </Table.Cell>
                  <Table.Cell>
                    <Input
                      fluid
                      transparent
                      name='fv'
                      ref={n => this.fv = n}
                    />
                  </Table.Cell>
                  <Table.Cell>
                    <Button
                      compact
                      size="tiny"
                      icon="add"
                      onClick={this.addData}
                    />
                  </Table.Cell>
                </Table.Row>
              </Table.Body>
            </Table>
          </Form>
        </div>
      </>
    );
  }
}

编辑反应表数组

There are few bugs in the code : 1. You dont need to setState inside render function.

//Your Code
this.setState({
        lista: [
          ...this.state.lista,
          { key: new_id + 1, model: "", sn: "", fv: "" }
        ]
      });

  1. You dont need to pass listener on onClick ie
this.props.rmveIndx(e.target.name || e.target.closest("button").name);

to (You dont need it. You can simply do this )

onTrash(e) {
    this.props.rmveIndx();
  }

  1. Instead of passing e.target.name || e.target.closest("button").name just pass object(it will easier if you required other data in future) ie

    {lista.map(object => <RowData
                      obj={object}
                      rmveIndx={() => this.removeListIndex(object)} //Note here
                      chVal={this.toDoChangeValues}
                    />)

  1. Filter data based on key :
removeListIndex(n) {
    this.setState(prevState => ({
      lista: prevState.lista.filter(row => row.key !== n.key)
    }));
  }

  1. Most important you have set all input value to defaultValue since its controlled component so you need to pass value in value props. Read document again for your clarity on semantic. I can explain but learn yourself ;-)
<Table.Row id={"id_" + this.props.obj.key}>
        <Table.Cell>
          <Input
            fluid
            transparent
            onChange={this.onTodoChange}
            name={"model_" + this.props.obj.key}
            placeholder="00000000000"
            defaultValue={this.props.obj.model}
            value={this.props.obj.model}
          />
        </Table.Cell>
        <Table.Cell>
          <Input
            fluid
            transparent
            onChange={this.onTodoChange}
            name={"sn_" + this.props.obj.key}
            placeholder="XXXXXXXXXXXXXXX"
            defaultValue={this.props.obj.sn}
            value={this.props.obj.sn}
          />
        </Table.Cell>
        <Table.Cell>
          <Input
            fluid
            transparent
            onChange={this.onTodoChange}
            defaultValue={this.props.obj.fv}
            value={this.props.obj.fv}
          />
        </Table.Cell>
        <Table.Cell>
          <Button
            name={this.props.obj.key}
            onClick={this.onTrash}
            color={this.state.trash ? "blue" : undefined}
            compact
            size="tiny"
            icon="trash"
          />
        </Table.Cell>
      </Table.Row>

Here is working code sandbox link : https://codesandbox.io/s/react-table-array-rinfw

Note : I commented some of your code. It just logic to guide how it works in it. you can comment and carry your code from here

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM