Reputation: 463
I have React JS app, which updating boostrap grid table with entries from ASP .NET Core Web API.
And I need to update the grid with new entries after inserting. I did that with help of componentDidUpdate()
and using refreshList()
function there, but I am getting an infinity loop of refreshList()
function.
Any thoughts about how to update the grid without that loop?
import React, {Component} from 'react';
import {Table, Container} from 'react-bootstrap';
import {Button, ButtonToolbar} from 'react-bootstrap';
import {AddDepModal} from './AddDepModal';
import {EditDepModal} from './EditDepModal';
export class Department extends Component {
constructor(props){
super(props);
this.state = {deps:[], addModalShow: false, editModalShow: false}
}
componentDidMount()
{
this.refreshList();
}
refreshList()
{
fetch("https://localhost:5001/api/departments")
.then(response=> response.json())
.then(data=> {
this.setState({deps:data});
});
}
componentDidUpdate()
{
this.refreshList();
}
render(){
const {deps, depid, depname} = this.state;
let addModalClose = () => this.setState({addModalShow:false})
let editModalClose = () => this.setState({editModalShow:false})
return (
<div>
<Table className = "mt-4" striped bordered hover size ="sm">
<thead>
<tr>
<th>DepartmentID</th>
<th>DepartmentName</th>
<th>Options</th>
</tr>
</thead>
<tbody>
{deps.map(dep=>
<tr key = {dep.id}>
<td>{dep.id}</td>
<td>{dep.name}</td>
<td>
<ButtonToolbar>
<Button
className ="mr-2" variant ="info"
onClick = {() => this.setState({editModalShow:true, depid: dep.id, depname: dep.name})}
>
Edit
</Button>
<EditDepModal
show = {this.state.editModalShow}
onHide = {editModalClose}
depid = {depid}
depname = {depname}/>
</ButtonToolbar>
</td>
</tr>
)}
</tbody>
</Table>
<ButtonToolbar>
<Button variant = "primary" onClick = {() => this.setState({addModalShow: true})}>Add Department</Button>
<AddDepModal
show ={this.state.addModalShow}
onHide ={addModalClose}/>
</ButtonToolbar>
</div>
)
}
}
Upvotes: 0
Views: 279
Reputation: 1154
Remove componentDidUpdate() because refreshData doesn't depend from props to fetch data and there aren't any checks with prevProps and newProps.
You can call refreshData method from Add or Save Button callback.
I image that you are saving data from modal code, add setState callback.
Modal save data, onhide set show state to false and call refreshData from once.
let addModalClose = () => this.setState({addModalShow:false}, this.refreshData)
Upvotes: 2
Reputation: 5205
You're calling this.refreshList();
which does some thing and then set the state. After the state is set, render
functions is called and in turn componentDidUpdate
is called again, setting the infinite loop. To make it work, compare from the previous props
and then call the this.refreshList();
if needed.
componentDidUpdate(prevProps) {
// Typical usage (don't forget to compare props):
if (this.props.depid !== prevProps.depid) { //Replace `depid` with the props you like to compare changes. If that is changed, then only call
this.refreshList();
}
}
You may call setState() immediately in componentDidUpdate() but note that it must be wrapped in a condition like in the example above, or you’ll cause an infinite loop. It would also cause an extra re-rendering which, while not visible to the user, can affect the component performance. If you’re trying to “mirror” some state to a prop coming from above, consider using the prop directly instead. Read more about why copying props into state causes bugs.
see the docs: https://reactjs.org/docs/react-component.html#componentdidupdate
Upvotes: 2
Reputation: 1620
The problem is you are calling refreshList
in componentDidMount and componentDidUpdate. As described in the documentation: https://reactjs.org/docs/react-component.html#componentdidupdate
you should at some condition to avoid an infinity loop in componentDidUpdate.
Upvotes: 1