Reputation: 7
I'm just learning React. I have two API calls to the backend MongoDB to pull names of vacations related to a user account. The names are saved to a JSON object and I'm trying to map through it to generate buttons on my React side but it's rendering nothing in that div. Everything else renders to the page. API calls are a mess because I thought that was the issue at first.
Profile Page
import React, { Component } from "react";
import Wrapper from "../components/Wrapper";
import { Container, Row, Col } from "../components/Grid";
import PastVacations from "../components/PastVacations";
import VacationBtn from "../components/VacationBtn"
import API from "../utils/API";
class Profile extends Component {
state = {
vacaIDs: [],
vacaNames: []
}
componentDidMount() {
this.getUser()
}
getUser = () => {
let IDsArr = []
API.getUser("Bill")
.then((res) => {
// console.log(res.data) Logs user found
res.data.vacations.forEach((VacaIDs) => {
let obj = {}
obj.name = VacaIDs;
IDsArr.push(obj)
// console.log(items) Logs Vacation IDs
})
console.log(IDsArr)
this.setState({
vacaIDs: IDsArr
})
this.getNames()
}).catch((err) => {
console.log(err)
})
}
getNames = () => {
let namesArr = []
this.state.vacaIDs.forEach((names) => {
console.log(names.name)// Logs vacation IDs
let obj = {}
API.getVacations(names.name).then((res) => {
console.log(res.data.name)// Logs Vacation names
obj.name = res.data.name;
namesArr.push(obj)
}).catch((err) => {
console.log(err.response)
})
})
this.setState({
vacaNames: namesArr
})
}
render() {
return (
<div className="">
<div className="row justify-content-around">
<div className="col-md-6">
{this.state.vacaNames.map(items => (
<VacationBtn
name={items.name}
/>
))}
</div>
<div className="col-md-4">
<div className="card">
<h5 className="card-header">
Card title
</h5>
<div className="card-body">
<p className="card-text">
Card content
</p>
</div>
<div className="card-footer">
Card footer
</div>
</div>
</div>
</div>
</div>
);
}
}
export default Profile;
VacationBtn Component
import React, { Component } from "react";
import "./style.css";
class VacationBtn extends Component {
render() {
return (
<button type="button" className="btn btn-primary">{this.props.name}</button>
);
}
}
export default VacationBtn;
Upvotes: 0
Views: 47
Reputation: 2651
As @chandan_kr_jha noticed you're updating state before API is finished it's work.
A bit fancier code below with the same idea behind:
getNames = async () => {
const promises = this.state.vacaIDs.map((names) => API.getVacations(names.name));
const vacations = await Promise.all(promises);
this.setState({
vacaNames: vacations.map(v => v.data.name),
});
};
Upvotes: 2
Reputation: 557
Use Promise.all Your current code is iterating for API calls but setState happens before any of the api calls are resolved.
getNames = () => {
let namesArr = [];
const promises = [];
this.state.vacaIDs.forEach((names) => {
promises.push(API.getVacations(names.name));
});
Promise.all(promises).then((values) => {
// do data manipulation here
values.forEach((val) => {
namesArr.push(val.data.name);
});
this.setState({
vacaNames: namesArr,
});
});
};
Upvotes: 2