Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React JS: how to properly remove an item from this.state.data where data is an array of objects

I have a component that generates a table with rows of data (<tr> etc.) based on an array of data retrieved via an AJAX call. Everything works well for editing and adding the data, but I am unable to determine how to make a distinct copy of the array (with distinct copies of the contained objects - by val, not by ref) so that when I remove the specified row of data, the applicable row is removed from the table.

Currently, because the contained objects are by ref, even when I make a copy of the array, my table has the last row removed (even though the row index and data is all correctly referenced and deleted in my AJAX call).

handleRowDelete: function(rowIdx) {
     // Correct row 
     var row = this.state.data[rowIdx];

     // This makes a new array, but the contained objects are still by ref
     var rows = this.state.data.slice();

     // This contains the proper row that will be deleted. If this array is set to data, the table is updated to reflect just the one row - as expected.
     var throwout = rows.splice(rowIdx, 1);
     console.log(throwout);

     // Whether I set via the React.addons: 
     var newState = React.addons.update(this.state, {
         data: { $set: rows }
     });
     this.setState(newState);

     // Or just set the state again via this.setState(...)
     //this.setState({data: rows, add: false});

     // It always just removes the last row in the component render
     // Even though the proper row gets deleted following in AJAX call
     $.ajax({
     ...
},
...    

I understand React can't make a proper diff so the render is not triggered, so can you show me how this should be handled?

UPDATE. Relevant loop:

var Grid = React.createClass({
    propTypes: {
        data: React.PropTypes.array.isRequired,
        onCellChange: React.PropTypes.func.isRequired,
        onRowCommit: React.PropTypes.func.isRequired
    },
    render: function() {
        var rows = this.props.data.map(function(rowData, index) {
            return <Row key={index} data={rowData} onCellChange={this.props.onCellChange.bind(null, index)} onRowCommit={this.props.onRowCommit.bind(null, index)} onRowDelete={this.props.onRowDelete.bind(null, index)} />;
        }, this);

        return (
            <Table striped bordered hover responsive>
              <thead>
              <tr>
                <th className="col-sm-4">Order Subtotal (up to)</th>
                <th className="col-sm-2">Canada</th>
                <th className="col-sm-2">US</th>
                <th className="col-sm-2">International</th>
                <th className="col-sm-1"></th>
              </tr>
              </thead>
              <tbody>
                    {rows}
              </tbody>
            </Table>  
        );
    }
});
like image 816
Ted Avatar asked Mar 10 '15 22:03

Ted


People also ask

How do I remove an item from an array React?

To remove an element from an array of objects in React: Use the filter() method to iterate over the array. On each iteration check if a certain condition is met. The filter method returns an array containing only the elements that satisfy the condition.

How do I delete a component in React?

React has a top-level API called unmountComponentAtNode() that removes a component from a specific container. The function unmountComponentAtNode() takes an argument as a container from which the specific component should be removed.

How do you filter an array in React?

To filter an array of objects in React: Call the filter() method on the array. On each iteration, check if a certain condition is met. The Array. filter methods returns an array with all elements that satisfy the condition.


2 Answers

You'll need to make sure that the key value remains a constant for the lifetime of the object instance. As you have it coded, the key value is based on the index into the Array. If you remove one element from the Array, the indexes are updated, and so would be the keys. And, as a result, an object's key would change, and React will appear to not properly apply the new array changes (even when the underlying array has changed).

You'll need to either use a unique value from each object instance as the key or create one artificially (just assign a unique number to each object).

like image 59
WiredPrairie Avatar answered Oct 13 '22 11:10

WiredPrairie


Use unique key is in Data Objects as below.

data = [
  {
    id: 0,
    contents: 'data 0',
  },
  {
    id: 3,
    contents: 'data 3',
  },
  {
    id: 4,
    contents: 'data 4',
  },
];


var rows = this.props.data.map(function(rowData, index) {
            return <Row key={rowData.id} data={rowData} onRowDelete={this.props.onRowDelete.bind(null, index)} />;
          }, this);

React do not re-render the component has the same key as one before.

like image 42
Jeff Gu Kang Avatar answered Oct 13 '22 10:10

Jeff Gu Kang