Reputation: 1136
I have a simple database in React where updates and deletions to the database are handled via Ajax.
After the successful Ajax call on the record component, the updated or deleted record is passed to the records component, which displays all of the records.
There, the handle methods below update the state of the records and re-render the results.
My issue is that while the handleDelete method works fine (and re-renders the records without the deleted record), the handleUpdate method does not and leaves the un-updated record until I refresh the page.
Any ideas why the setState in the handleUpdate wouldn't re-render the results?
Below is the code:
class Sites extends React.Component {
constructor (props) {
super(props);
this.handleUpdate = this.handleUpdate.bind(this);
this.handleDelete = this.handleDelete.bind(this);
this.state = {records: this.props.records};
}
handleUpdate (record) {
let records = this.state.records;
let index = records.map((x) => {return x.id}).indexOf(record.id);
records.splice(index, 1, record);
this.setState({records: records}); # this doesn't re-render the results
}
handleDelete (record) {
let records = this.state.records;
let index = records.map((x) => {return x.id}).indexOf(record.id);
records.splice(index, 1);
this.setState({records: records}); # this re-renders the results
}
render () {
let records = this.state.records.map((record) => {
return (
<Record record={record} key={record.id} handleUpdateRecord={this.handleUpdate} handleDeleteRecord={this.handleDelete}/>
);
});
return (
<div className="col-sm-9">
<table className="table table-striped">
<thead>
<tr>
<th>Name</th>
<th>City</th>
<th>State</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{records}
</tbody>
</table>
</div>
);
}
}
Upvotes: 0
Views: 3170
Reputation: 1030
A simple
componentWillReceiveProps() {}
fires when the props is received and will use the updated state.
Upvotes: 0
Reputation: 12136
You should always treat the state as immutable and never, ever modify it directly. Copy its contents, modify the copy and set it again.
I have prepared a pen where I have improvised an implementation for your <Record />
and rewritten the onUpdate
and onDelete
logic, treating the state as immutable, creating a new records
array by either mapping or filtering the old one and setting it again. See it here. I have renamed a couple of things, but it's mostly the same!
These are the important bits:
handleUpdate (record) {
const records = this.state.records.map(r => {
if (r.id !== record.id) return r;
return record;
})
this.setState({records})
}
We receive the updated record and map the old array: if we find the element with the sameid
as the new one, we return the latter, otherwise we return the original element. map
returns a new array, so we are safe.
handleDelete (id) {
const records = this.state.records.filter(r => r.id !== id)
this.setState({records})
}
Here we just need the id, and we filter the records
array on the state, leaving out the element with the id
we want to delete. Again, filter
returns a new array, so we are good.
Hope this helps!
Upvotes: 3