I am having the issue of data not being rendered from API response in React even though I do receive it.
I have the following "Admin-Notification" component:
import React from "react";
import './Admin-notifications.css';
import axios from 'axios';
class AdminNotifications extends React.Component {
constructor(){
super();
this.state = {
events:[
{
"id": 1,
"name": "Fotosinteza plantelor",
"start_date": 1637496120,
"end_date": 4098071460,
"location": "Cluj-Napoca",
"description": "Aduceti planta",
"status": "pending",
"id_organizer": 2,
"id_type": 1
},
{
"id": 2,
"name": "Cantecul greierilor de peste imas",
"start_date": 1637669280,
"end_date": 4098071460,
"location": "Imas",
"description": "In padurea cu alune aveau casa 2 pitici",
"status": "pending",
"id_organizer": 2,
"id_type": 1
},
{
"id": 4,
"name": "test",
"start_date": 1637518260,
"end_date": 4098071460,
"location": "test",
"description": "test",
"status": "pending",
"id_organizer": 2,
"id_type": 1
}
]
}
this.state2={
events:[],
}
}
getEvents(){
axios
.get("http://127.0.0.1:8000/api/getevents")
.then(response =>{
this.state2.events = response.data;
})
.catch(err => console.log(err));
};
render(){
this.getEvents();
console.log(this.state);
console.log(this.state2);
const {events} = this.state2;
return(
<main className="mw6 center main">
{
events.map((event)=>{
return(
<article key={event.id} className="dt w-100 hight padd bb pb2 component" href="#0">
<div className="col-md-3">
<div className="dtc w2 w3-ns v-mid">
{/* <img src={event.img}
alt="event image from organizator"
className="ba b--black-10 db br-100 w2 w3-ns h2 h3-ns"/> */}
</div>
<div className="dtc v-mid pl3">
<h1 className="f6 f5-ns fw6 lh-title black mv0">{event.name} </h1>
<h2 className="f6 fw4 mt0 mb0 black-60">{event.description}</h2>
</div>
<div className="dtc v-mid">
<form className="w-100 tr">
<button className="btn" type="submit">Accept</button>
</form>
</div>
<div className="dtc v-mid">
<form className="w-100 tr">
<button className="btn" type="submit">Decline</button>
</form>
</div>
</div>
</article>
)})
}
</main>
)
}
}
export default AdminNotifications;
There, you can see that I have two states: state and state2. "this.state" is a hard-coded variant of the data that is coming from the API and "this.state2" is the data that came from the API.
Here is a picture of the console.log() from the render(), where first 'events' belongs to "state" and second one belongs to "state2":
Here is how the website looks like if we map using "state":
const {events} = this.state;
return(
<main className="mw6 center main">
{
events.map((event)=>{
...
This is fine, this is how I want the website to look like.
And here is how it looks like using the data from the API:
const {events} = this.state2;
return(
<main className="mw6 center main">
{
events.map((event)=>{
...
Here are the API calls:
I can also provide you with the backend code.
View of the API:
@api_view(['GET'])
def getevents(request):
if request.method == "GET":
events = Event.objects.all()
serializer = EventSerializer(events, many=True)
return Response(serializer.data)
Yes, I did take care that there are no overwrites. This is the only view for this path.
Here is the Serializer that I have used:
class EventSerializer(serializers.ModelSerializer):
class Meta:
model = Event
fields = '__all__'
Here is the model of the "Event":
class Event(models.Model):
name = models.TextField()
id_organizer = models.ForeignKey(User, on_delete=CASCADE, db_column='id_organizer')
start_date = models.BigIntegerField()
end_date = models.BigIntegerField()
location = models.TextField()
description = models.TextField()
id_type = models.ForeignKey(EventType, on_delete=CASCADE, db_column='id_type')
status = models.CharField(max_length = 50)
class Meta:
db_table="events"
Here is the table's database from where I get the data:
I did a print before returning the data in Django. Here is the result:
@api_view(['GET'])
def getevents(request):
if request.method == "GET":
events = Event.objects.all()
serializer = EventSerializer(events, many=True)
print(serializer.data)
return Response(serializer.data)
As you may have noticed, the API got called twice. I cannot really explain why this is happening, but in order to confirm this, if I add a console.log() inside the function that calls the API, and I get the console.log() twice, meaning that the function does calls twice.
getEvents(){
axios
.get("http://127.0.0.1:8000/api/getevents")
.then(response =>{
this.state2.events = response.data;
console.log("test1");
})
.catch(err => console.log(err));
};
Picture:
I have no idea why it is being called twice. But I do suspect it is one of the problems.
And here are the URL paths:
urlpatterns = [
path('api/login', views.login),
path('api/addevent', views.addevent),
path('api/getevents', views.getevents),
]
I have tried to use a Promise type, parsing in different ways the data and pushing it to "state2", returning the data into the render directly but nothing really worked.
CodePudding user response:
Solution found:
constructor(){
super();
this.state = {
events:[]
}
}
componentDidMount(){
axios
.get("http://127.0.0.1:8000/api/getevents")
.then(response =>{
this.setState({events: response.data});
})
.catch(err => console.log(err));
}
To be honest, I have no idea why it wouldn't work the other way. But glad to have this problem solved.
CodePudding user response:
You cannot manipulate the state directly and have to use the this.setStae function to update it like below
getEvents(){
axios
.get("http://127.0.0.1:8000/api/getevents")
.then(response =>{
this.setState({events:response.data})
console.log("test1");
})
.catch(err => console.log(err));
};