Why is my react Table not updating the data?
Asked Answered
K

3

6

I got a react Table that I want to delete or modify my data. My code is below for all my cells.

    deleteTableElement = (row) => {
        let data = this.state.list.data;
        data.splice(row.id, 1);
        this.setState({
            list:{
                ...this.state.list,
                data:data
            }
        })
    };

    actionsCell = (columns) => {
        columns.push({
            Header: "Accion",
            Cell: (props) => {
                console.log(props);
                return (
                    <div
                        style={{
                            display: "flex",
                            justifyContent: "space-around",
                        }}
                    >
                        <i
                            onClick={() => this.deleteTableElement(props.row)}
                            className="material-icons"
                            style={{ color: "red", cursor: "pointer" }}
                        >
                            delete
                        </i>
                    </div>
                );
            },
        });
        return columns;
    };

In this case, I want to modify the item. The react table is not updating.

Kidderminster answered 26/4, 2021 at 7:33 Comment(22)
How di you call ` actionsCell ? and what is data structure of columns`?Hindemith
is setState not enought? i mean i thought that was the wayKidderminster
Any reason for async inactionsCell ?Ervinervine
@MichaelRovinsky nop, i got a solution for edit content just with e.values = {...e.values, id:xvar}, now i need the solution for deleting a rowKidderminster
I cannot understand your code. Can you post some data and a markup example of the table you try to render?Ervinervine
Don't mutate state - splice mutates state. Don't do it. Use filter instead.Flawed
@MichaelRovinsky im trying to delete a row, just that, im sorry for my code : /, i pass the data from my state, when i change my state react table didnt change the dataKidderminster
OK, put console.log(this.state.list); before and after splice.Ervinervine
@MichaelRovinsky the item was removed from state, but my table still doesnt changeKidderminster
Because your render depends on the props, not on the stateErvinervine
@MichaelRovinsky - no, it's because he mutated state.Flawed
this is how i send the data <DataTable {...this.state.list} />Kidderminster
@Adam i did your solution, but i doesnt change :/Kidderminster
@Adam OK, I seeErvinervine
@MichaelRovinsky - based on the partial code that the OP is showing and described in a comment on my answer, I'm thinking you could be right and the OP doesn't actually need state here at all. It's hard to tell.Flawed
@ReinaldoPastran maybe it's a good idea to describe clearly the whole component and its data and rewrite it in a snippet or fiddleErvinervine
@MichaelRovinsky - you're right, this question can't be answered without a reproducible stackblitz, or something of that nature.Flawed
stack doesnt let me edit and paste all of my code : / the render is like (!this.state.list) ?return "Loading...": <DataTable {...this.state.list} />Kidderminster
componentDidMount start with a fetchKidderminster
@MichaelRovinsky Do you know where I can see an example to eliminate a row?Kidderminster
@ReinaldoPastran an example of table that deletes a row on click?Ervinervine
@MichaelRovinsky yes react-table.tanstack.com doesnt have 1Kidderminster
F
11

Whenever your component unexpectedly doesn't update, it's because you're mutating state. Literally 100% of the time:

        let data = this.state.list.data;
        data.splice(row.id, 1); // <- splice mutates an array, mutating state is bad
        this.setState({
            list:{
                ...this.state.list,
                data:data
            }
        })

should be:

        this.setState({
            list:{
                ...this.state.list,
                data:data.filter((d,i) => i !== row.id)
            }
        })
Flawed answered 26/4, 2021 at 10:57 Comment(6)
i did it, this is how i set my data in react Table const [datas, setDatas] = React.useState(data); const defaultColumn = React.useMemo( () => ({ Filter: DefaultColumnFilter, }), [] ); React.useEffect(() => { setDatas(data); }); Kidderminster
@ReinaldoPastran - I have no idea what that code means, all I know is that when I see somebody splice-ing (or otherwise mutating) a state variable, I know immediately what is wrong.Flawed
@ReinaldoPastran - although what that code does indicate to me is that you might not be clear on the difference between props and state - it appears possible that your component should not be using state at all and instead should just be rendering based on props, but I'd need to see your actual full code in order to determine that.Flawed
How do I make the state depend on the propertiesKidderminster
@ReinaldoPastran - This component doesn't own this data - this data is owned (has it's source of truth, state) by another component and just passes the data into this one (via props) to render it. So, instead of having state in this component - you should just use the props passed in to render the data. Additionally, the component that passes in the data to this one should also pass in a handleDelete function prop, this component will call that when the user pushes a button. The work of deleting the row is done in the component that owns the data, which is not this one.Flawed
idk why this didnt works last time, now i see this is the best way thank you mateKidderminster
E
3

Here is a simple example of a table with deletable rows.

Pass your initial rows to the component as a prop and copy them to the state.

On click delete button, make a copy or rows without deleted row and update the state. The table will re-render.

const {useState} = React;

const MyTable = ({rows, columns}) => {
  const [data, setData] = useState(rows); // Copy rows to the state
  
  const deleteRow = index => {
    // Create a copy of row data without the current row
    const newData = [...data.slice(0, index), ...data.slice(index + 1)];
    // Update state
    setData(newData);
  }

  return (
    <table cellSpacing="0" cellPadding="10">
    <thead>
      <tr>
        {columns.map(column => (<th key={column}>{column}</th>))}
        <th/>
      </tr>
    </thead>
    <tbody>
      {data.map((row, index) => (
        <tr key={index}>
          <td>{row.text}</td>
          <td>{row.value}</td>
          <td>
            <button onClick={() => deleteRow(index)}>Delete Me !</button>
          </td>
        </tr>
      ))}
    </tbody>  
    </table>
    )
}

const tableRows = [
  {
    text: 'A',
    value: 100,
  },
  {
    text: 'B',
    value: 200,
  },
  {
    text: 'C',
    value: 300,
  },
  {
    text: 'D',
    value: 400,
  },
];

const tableColumns = ['Text', 'Count'];


ReactDOM.render(
  <MyTable rows={tableRows} columns={tableColumns} />,
  document.getElementById('container')
);
th, td {
  border: 1px solid gray; 
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="react"></div>

<div id="container">
</div>
Ervinervine answered 26/4, 2021 at 12:25 Comment(7)
friend I think it's my fault for not explaining well, I'm using the reactTable API, and I need to remove the data from that component react-table.tanstack.comKidderminster
@Adam it's based on assumption that the initial rows data is immutable, so the state is a subset of the passed prop. There is an alternative: pass an update callback as a prop and call it when a row is deleted. In that case the state will become obsoleteErvinervine
@ReinaldoPastran I see. You can do it with react-table exactly the same way: bind an event to a button click, remove rows from your data, update the state and then your table will re-render with the new dataErvinervine
<i onClick={() => this.deleteTableElement(props.row)} className="material-icons" style={{ color: "red", cursor: "pointer" }} > delete </i> there is the event with bind or an arrow function deleteTableElement = (row) => { let data = this.state.list.data; data.splice(row.id, 1); this.setState({ list:{ ...this.state.list, data:data } }) };Kidderminster
OK, now replace splice with a code similar to snippet's one and make sure you don't update the state with the same array (event when it's smaller, it has the same ref as before splice). The code with [...slice, ...slice] builds a new array and updates the state properlyErvinervine
@MichaelRovinsky There is an alternative: pass an update callback as a prop and call it when a row is deleted. In that case the state will become obsolete <- Not doing this is what's causing all the confusion in this question. This component doesn't own this data, some parent component does, all the manipulation of this data is being handled in the wrong place.Flawed
@Adam definitely!Ervinervine
K
0

thanks to @Adam and @MichaelRovinsky , theres the result and my problems are fixed with the function slice, the component state should be update with a copy

let data = this.state.list.data;
        data.splice(row.id, 1);
        const copy = data.slice();
        this.setState({
            list: {
                ...this.state.list,
                data: copy,
            },
        });
Kidderminster answered 26/4, 2021 at 13:25 Comment(1)
🤦 don't use splice. Working and done correctly are two different things.Flawed

© 2022 - 2024 — McMap. All rights reserved.