Peter
Peter

Reputation: 501

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>
    );
  }
}

Upvotes: 0

Views: 1448

Answers (2)

Osman Safak
Osman Safak

Reputation: 255

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>
      </>
    );
  }
}

Edit react-table-array

Upvotes: 1

Shubham Verma
Shubham Verma

Reputation: 5054

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 i.e
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) i.e

    {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

Upvotes: 0

Related Questions