I have this parent component called ListGyms. This is a component that renders a table. In the each row of the table you can see a gym record fetched from the API and two buttons. The buttons render 2 different child components (ViewMembers or EditGym). Each of these child components are rendered one at a time conditionally (depending on which button in the row of the table is being clicked).
My trouble is in my EditGym component. Everything works correctly when sending a PUT request to the API, however, the ListGyms component does not update its state once this PUT request from EditGym has been called.
I have tried to make it work using componentDidUpdate() method in my ListGyms component, but unfortunatelly me website is lagging and constantly sending a network requests. The component is stuck in an infinity loop.
I have tried to solve my problem in several ways, but I failed. I have tried passing the method fetchingGyms as a prop to my child component EditGym, and later calling this prop function onSubmit, but I got the error this.setState is undefined. I am out of ideas really.
Here is my code:
ListGyms.js
import 'bootstrap/dist/css/bootstrap.min.css';
import { Spinner } from 'react-bootstrap';
import '../App.css';
import axios from 'axios';
import ViewMembers from './ViewMembers';
import EditGym from './EditGym';
import { unmountComponentAtNode } from 'react-dom';
class ListOfGyms extends React.Component {
constructor(props) {
super(props)
this.state = {
gyms: [],
isItClicked: false,
isItClickedMember: false,
isFetching: true,
checkForUpdate: true,
}
this.handleChange = this.handleChange.bind(this);
this.handleChangeForMember = this.handleChangeForMember.bind(this);
}
componentDidMount() {
this.fetchingGyms();
}
componentDidUpdate(prevProps, prevState) {
if(prevState.gyms !== this.state.gyms){
this.fetchingGyms();
}
}
async fetchingGyms(){
axios.get('https://localhost:44345/api/gyms')
.then(res => {
const gyms = res.data;
this.setState({ gyms, isFetching: false });
console.log("GYMS", gyms);
})
.catch(err => {
console.log(err);
})
}
handleChange = (e) => {
e.preventDefault();
this.setState({
isItClicked: true,
isItClickedMember: false,
id: e.target.value
}, () => {
console.log("e", e.target.value);
console.log("id", this.state.id);
});
}
handleChangeForMember = (e) =>{
this.setState({
isItClickedMember: true,
isItClicked: false,
id: e.target.value
}, () => {
console.log("e", e.target.value);
console.log("id", this.state.id);
});
}
renderTableData() {
return this.state.gyms.map((gym) => {
return (
<tr key={gym.gymID}>
<td>
<label for="gymName">Gym Name: {gym.gymName}</label>
</td>
<td>
<button value={gym.gymID} onClick={this.handleChange}>Edit</button>
</td>
<td>
<button value={gym.gymID} onClick={this.handleChangeForMember}>View Members</button>
</td>
</tr>
)
})
}
render() {
const isFetching = this.state.isFetching;
if (isFetching){
return (
<Spinner animation="border" variant="primary" />
)
}
if (this.state.isItClicked) {
return (
<>
<div class="container" className="ListOfGyms">
<div class="row">
<div class="col-sm-6">
<h2>List of Gyms</h2>
</div>
</div>
<table id='gyms' class="table table-dark">
<tbody>
{this.renderTableData()}
</tbody>
</table>
</div>
<EditGym id={this.state.id}/>
</>
)
}
if (this.state.isItClickedMember) {
return (
<>
<div class="container" className="ListOfGyms">
<div class="row">
<div class="col-sm-6">
<h2>List of Gyms</h2>
</div>
</div>
<table id='gyms' class="table table-dark">
<tbody>
{this.renderTableData()}
</tbody>
</table>
</div>
<ViewMembers id={this.state.id}/>
</>
)}
return (
<div class="container" className="ListOfGyms">
<div class="row">
<div class="col-sm-6">
<h2>List of Gyms</h2>
</div>
</div>
<table id='gyms' class="table table-dark">
<tbody>
{this.renderTableData()}
</tbody>
</table>
</div>
)
}
}
export default ListOfGyms;
EditGym.js
import React from 'react';
import axios from 'axios';
import { Spinner } from 'react-bootstrap';
class EditGym extends React.Component {
constructor(props) {
super(props);
this.state = {
GymName: '',
gym_description: '',
address_line1: '',
address_line2: '',
state: '',
postcode: '',
Country: '',
isFetching: true,
}
this.onChangeGymsName = this.onChangeGymsName.bind(this);
this.onChangeGymsDescription = this.onChangeGymsDescription.bind(this);
this.onChangeAddressLine1 = this.onChangeAddressLine1.bind(this);
this.onChangeAddressLine2 = this.onChangeAddressLine2.bind(this);
this.onChangeState = this.onChangeState.bind(this);
this.onChangePostCode = this.onChangePostCode.bind(this);
this.onChangeCountry = this.onChangeCountry.bind(this);
this.onSubmit = this.onSubmit.bind(this);
}
onChangeGymsName(e) {
this.setState({
GymName: e.target.value
});
}
onChangeGymsDescription(e) {
this.setState({
gym_description: e.target.value
});
}
onChangeAddressLine1(e) {
this.setState({
address_line1: e.target.value
});
}
onChangeAddressLine2(e) {
this.setState({
address_line2: e.target.value
});
}
onChangeState(e) {
this.setState({
state: e.target.value
});
}
onChangePostCode(e) {
this.setState({
postcode: e.target.value
});
}
onChangeCountry(e) {
this.setState({
Country: e.target.value
});
}
componentDidMount(){
this.setState({ isFetching: false})
}
onSubmit(e) {
var id = this.props.id;
e.preventDefault();
const obj = {
GymName: this.state.GymName,
gym_description: this.state.gym_description,
address_line1: this.state.address_line1,
address_line2: this.state.address_line2,
State: this.state.state,
postcode: this.state.postcode,
Country: this.state.Country
}
axios.put(`https://localhost:44345/api/gyms/${id}/`, obj)
.then(res => console.log(res.data));
}
render() {
const isFetching = this.state.isFetching;
if (isFetching){
return (
<Spinner animation="border" variant="primary" />
)
}
return (
<div class="form-group">
<h2>Edit the Gym Infomation</h2>
<form onSubmit={this.onSubmit}>
<div>
<label htmlFor="gymName" class="form-check-label">Gym Name</label>
<input name="gymName" value={this.state.GymName} onChange={this.onChangeGymsName} class="form-control" placeholder="Gym Name"/>
</div>
<div>
<label htmlFor="gymDescription" class="form-check-label">Description</label>
<input name="gymDescription" value={this.state.gym_description} onChange={this.onChangeGymsDescription} class="form-control" placeholder="Description"/>
</div>
<div>
<label htmlFor="addressLine1">Address Line 1</label>
<input name="addressLine1" value={this.state.address_line1} onChange={this.onChangeAddressLine1} class="form-control" placeholder="Address Line 1"/>
</div>
<div>
<label htmlFor="addressLine2">Address Line 2</label>
<input name="addressLine2" value={this.state.address_line2} onChange={this.onChangeAddressLine2} class="form-control" placeholder="Address Line 2"/>
</div>
<div>
<label htmlFor="state">State</label>
<input name="state" value={this.state.state} onChange={this.onChangeState} class="form-control" placeholder="State"/>
</div>
<div>
<label htmlFor="postCode">Postcode</label>
<input name="postCode" value={this.state.postcode} onChange={this.onChangePostCode} class="form-control" placeholder="Postcode"/>
</div>
<div>
<label htmlFor="country">Country</label>
<input name="country" value={this.state.country} onChange={this.onChangeCountry} class="form-control" placeholder="Country"/>
</div>
<button class="form-control" type="submit">Update a Gym Values</button>
</form>
</div>
)
}
}
export default EditGym;