How to remove selected index of an array from the DOM and reflect the change in React state?

Viewed 217

In my react app, I have an array of objects data that gets render to the table. The data structure of the data that I have is in the following format:

this.state = {
  inspectionViewAllRsData: [
    {
      INSPN_PERFORMER_CD: {label: "Contractor", value: "C"}
    },
    {
      INSPN_RSN_CD: {label: "Initial", value: "INIT"}
    },
    {
      INSPN_STS_CD: {label: "", value: "1000"}
    }
  ]
}

and here's my code for the table:

<table>
  <tr>
    <th>Performed By</th>
    <th>Inspection</th>
    <th>Residence Size</th>
  </tr>
  {this.state.inspectionViewAllRsData.map((item, i) => (
    <tr>
      <td>{item.INSPN_PERFORMER_CD.label} <button id="close-btn" onClick={() => this.handleRemove(i)}>X</button></td>
      <td>{item.INSPN_RSN_CD.label}</td>
      <td>{item.RSDNC_SIZE_QTY.value}</td>
    </tr>
  ))}
</table>

What I want to do is remove the selected index of an array from the state when I click on the "X" button. This is what I tried to do but it's giving me an error that row.filter is not a function

handleRemove = index => {
  const newData = this.state.inspectionViewAllRsData.map(row => {
    return row.filter((el, i) => i !== index);
  });
  console.log(newData)
  this.setState({ inspectionViewAllRsData: newData });
}

Can someone please help me with my functionality? Any help would be appreciate it.

2 Answers

You were very close. You just tried to do too much, using map to filter on each individual element of the array - which isn't possible because these are objects, not arrays. You simple want a top-level filter. Replace the definition of newData with this and all should be fine:

const newData = this.state.inspectionViewAllRsData.filter((el, i) => i !== index);

I don't know how you managed to render this, because it seems to me that you're confusing data structures and implementations.

In particular:

{this.state.inspectionViewAllRsData.map((item, i) => (
   <tr>
      <td>{item.INSPN_PERFORMER_CD.label} <button id="close-btn" onClick={() => this.handleRemove(i)}>X</button></td>
      <td>{item.INSPN_RSN_CD.label}</td>
      <td>{item.RSDNC_SIZE_QTY.value}</td>
    </tr>
  ))}

Every item is something like:

{ 
   property: {label: "string", value: "string"} 
}

So you basically have an array of 3 elements which are Object type and you're trying to render them all when just one of them is selected by the map function.

I guess you meant to have an array of objects (Object[]) in which every single Object has 3 properties, so your "hard-coded" data should look like this:

inspectionViewAllRsData = [
   {
      INSPN_PERFORMER_CD: {label: "Contractor", value: "C"},
      INSPN_RSN_CD: {label: "Initial", value: "INIT"},
      INSPN_STS_CD: {label: "", value: "1000"}
   },
   // Other Objects with this structure
]

I hope what I wrote is clear enough and that I guessed your intentions right, if not, please tell me and I'll edit my answer.

EDIT

I think you should parse your input in a more easy to read/work with data structure. This is my attempt and I'll try to explain my thought process.

In your state you should add another empty array:

this.state= {
   inspectionBlaBlah: //your initial data structure,
   newDataArray: []
}

In your constructor you should add an Object that will be useful to reorganize your data:

let toFillWithProperties = {};

After that u should do something like this:

inspectionViewAllRsData.map(
            // Cycle through your initial array
            (item, i) => {
                // Cycle through the properties of every item of your array
                return Object.keys(item).map(
                    (property, j) => {
                        // Create the same key/value for each property in your new object
                        toFillWithProperties[property] = item[property];
                        if ((i + 1) % 3 == 0){
                            // Every 3 steps you update your new Array
                            this.state.newDataArray.push(toFillWithProperties);
                            toFillWithProperties = {};
                        }
                    }
                )})

Once this is done you can then render the table like you were doing before but you should use the map function on this.state.newDataArray. The same applies for your handler function, use setState on your newDataArray.

It should work this way, but I really don't encourage you to work with this kind of data because this procedure is assuming that every 3 elements of your array they would repeat in structure, it won't work in any other cases.

Related