Reputation: 1510
I'm very new to React and although made some progress that I'm happy with, I've hit a snag that I'm stuck with and have been for over a day.
I'm creating a small app that uses React at the frontend and a .NET Core API server-side to supply the data.
So far, the following code works:
import React, { Component } from 'react';
export class LGSRValidation extends Component {
displayName = LGSRValidation.name
constructor(props) {
super(props);
this.state = { lgsr: [], loading: true };
fetch('api/FormValidation/LGSR')
.then(response => response.json())
.then(data => {
this.setState({
lgsr: data,
loading: false
});
});
}
static renderLGSRTable(lgsr) {
return (
<table className='table'>
<thead>
<tr>
<th>Job Number</th>
<th>Job Type</th>
<th>UPRN</th>
<th>Gas Register Number</th>
<th>Service Date</th>
</tr>
</thead>
<tbody>
<tr key={lgsr.jobnumber}>
<td>{lgsr.jobNumber}</td>
<td>{lgsr.jobType}</td>
<td>{lgsr.uprn}</td>
<td>{lgsr.gasRegisterNumber}</td>
<td>{lgsr.serviceDate}</td>
</tr>
</tbody>
</table>
);
}
render() {
let contents = this.state.loading
? <p><em>Loading...</em></p>
: LGSRValidation.renderLGSRTable(this.state.lgsr);
return (
<div>
<div>
<h1>{this.displayName}</h1>
<p>This component demonstrates fetching data from the server.</p>
{contents}
</div>
</div>
);
}
}
What it quite simply does is call my API to return a single object to the client-side code and render each property within the object into a separate table column.
What I'm trying to do is introduce a button that onClick
will call the API again, pull a new object and change the values in the table for the new property values. I'm happy with my server-side code and the creation of the random objects but my client side code is just not working.
I'm introducing the button within the parent tags of the component like this:
render() {
let contents = this.state.loading
? <p><em>Loading...</em></p>
: LGSRValidation.renderLGSRTable(this.state.lgsr);
return (
<div>
<div>
<h1>{this.displayName}</h1>
<p>This component demonstrates fetching data from the server.</p>
{contents}
</div>
<button onClick={this.getData}>
Next
</button>
</div>
);
}
Which seems to render fine. I'm also introducing a getData
function like this further up:
getData() {
fetch('api/FormValidation/LGSR')
.then(response => response.json())
.then(data => {
this.setState({
lgsr: data,
loading: false
});
});
this.setState({
contents : this.state.lgsr
});
}
I suspect it's at this part where I'm going wrong.
Please can you advise how I can click my new button to call the API, return some data and pass the properties of the lgsr
object into the corresponding table columns; replacing the previous data with the new data.
Upvotes: 3
Views: 1958
Reputation: 135
What are you trying to achieve here? Can you paste your final code?
I see something terrible here. Your 'loading' is already declared in your component state and you're updating 'contents' state with the lgsr data. And in your render, you have declared contents as this.state.loading
constructor(props) {
super(props);
this.state = { lgsr: [], loading: true };
/*some code here*/
getData () {
fetch('api/FormValidation/LGSR')
.then(response => response.json())
.then(data => {
this.setState({
lgsr: data,
loading: false
});
});
this.setState({
contents : this.state.lgsr
});
}
render() {
let contents = this.state.loading
Upvotes: 0
Reputation: 2444
I see 4 ways to improve your code:
Load data in the componentDidMount
lifecycle method instead of the component's constructor (more info). This should not be related to you problem but it's safer to ensure the component did mount before you possibly set the state.
As SGhaleb mentioned be sure that your getData
function is bound, either using an arrow function or the bind alternative, otherwise this.getData
is undefined and the button's onClick
should be a no op. You could use getData
for your initial request to not have duplicated code in your class.
In getData
you set the state's content
property, but you do it outside of the request's callback. It's value may be either the new or the old lgsr object of the new request. Check that you do want this or move it to the fetch callback.
Use a dedicated component to render the LGSR table instead of using a static render method and pass the required data via props to it. Again, nothing to do with your question.
Upvotes: 3
Reputation: 1007
You need to bind your getData()
to your constructor so you can use this
for your component rather than the current function.
this.getData = this.getData.bind(this);
A quicker way is to use arrow function like the following...
getData = () => {....}
This should hopefully fix your problem and allow you to use this.state
Upvotes: 3