I make two API call. Data from getAllCampaign api renders but for loadStats It appears React goes ahead to build a table without the data, thus throwing error of
Uncaught TypeError: Cannot read property 'data' of undefined
Here's what I'm doing.
coreapihelpers:
export const getAllCampaign = () => {
return fetch(`https://api.truepush.com/api/v1/listCampaign/1`, {
method: "GET",
headers: {
Authorization: `$TOKEN`,
"Content-Type": "application/json",
},
})
.then(response => {
return response.json()
})
.catch(err => console.log(err))
}
export const loadStats = async () => {
const ids = await getAllCampaign()
const data = Promise.all(
ids.data.map(async (i) => await (await fetch(`https://api.truepush.com/api/v1/campaignStats/${i.campaignId}`, {
method: "GET",
headers: {
Authorization: ``$TOKEN``,
"Content-Type": "application/json"
}
})).json())
)
return data
};
allData output is delayed on console
Full code :
import React, {useState, useEffect} from 'react';
import {getAllCampaign, loadStats} from "../helpers/coreapihelpers";
const TableRow = () => {
const [campaigns, setCampaigns] = useState([]);
const [stats, setStats] = useState([]);
const loadAllCampaigns = () => {
getAllCampaign()
.then(data => { setCampaigns(data.data) })
.catch(err => { console.log(err) });
};
const loadAllStats = () => {
loadStats()
.then(data => { setStats(data) })
.catch(err => { console.log(err) });
}
useEffect(() => {
loadAllCampaigns();
loadAllStats();
}, [])
const allData = campaigns.map ? campaigns.map((campaign, i) => ({
...campaign,
...stats[i],
}))
: <h1>API LIMIT EXCEEDS</h1>
return (
<div className="container">
<div className="row">
<div className="col-xs-12">
{allData.map ? allData.map((campaigns, index) => (
<div className="table-responsive" data-pattern="priority-columns">
<table className="table table-bordered table-hover">
<thead>
<tr>
<th>Sr. No</th>
<th>Campaign Id</th>
<th>Campaign Name</th>
<th>Campaign Status</th>
<th>Reach</th>
<th>Sent</th>
<th>Delivered</th>
<th>Views</th>
<th>Clicks</th>
<th>Unsubscribers</th>
</tr>
</thead>
<tbody>
<tr key={index}>
<td>{index + 1}</td>
<td>{campaigns.campaignId}</td>
<td>{campaigns.campaignTitle}</td>
<td>{campaigns.campaignStatus}</td>
<td>{campaigns.data.Reach}</td>
<td>{campaigns.data.Sent}</td>
<td>{campaigns.data.Delivered}</td>
<td>{campaigns.data.Views}</td>
<td>{campaigns.data.Clicks}</td>
<td>{campaigns.data.Unsubscribers}</td>
</tr>
</tbody>
</table>
</div>)) : <h1>API Limit Exceeds / API Token Broken</h1>}
</div>
</div>
</div>
);
}
export default TableRow;
I think the problem is that you should be checking whether state campaigns has been populated, not allData. allData is a variable, not the actual state. Actual state should be used for conditional rendering. Try this:
Replace this:
allData.map ? allData.map((campaigns, index)
With this:
campaigns ? allData.map((campaigns, index)
However, you should create an object for state that contains both campaigns and stats, since you intend to use them as corresponding items. Or, your database query should return them as one item with some time of join.
Try this for a client side solution:
const [stateObj, setObj] = useState([]);
const campaigns = [];
const stats = [];
const loadAllState = async () => {
try {
campaigns = await getAllCampaign();
} catch (err) {
console.log(err)
}
try {
stats = await loadStats();
} catch (err) {
console.log(err)
}
setObj(campaigns.map((campaign, i) => ({
...campaign,
...stats[i],
})))
};
useEffect(() => {
loadAllState();
}, [])
Then:
stateObj ? stateObj.map((campaigns, index)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With