I have a parent component called Dashboard and child component called DashboardTable. I'm able to successfully make an async graphql call in the parent element and pass the data to the child component.
Problem: The props data takes a second to load so it returns undefined for a second before getting the data (verified using console.log()). That delay causes an error in the mapping function. Error: Cannot read properties of undefined (reading 'map')
Question: How do I make the render wait for the prop data to load before rendering. I tried a conditional like this {this.props.data == undefined ? (wait) : (render)}
but that didn't work (same error).
Here is my code. Please let me know what I'm doing wrong
DashboardTable (child)
import React from "react";
import "bootstrap/js/src/collapse.js";
import Navigation from "../Navigation";
import { Link } from "react-router-dom";
import { API } from "@aws-amplify/api";
import config from "../../aws-exports";
import * as queries from "../../graphql/queries";
export class DashboardTable extends React.Component {
constructor(props) {
super(props);
}
render() {
console.log(this.props.data.data); // !!this returns undefined one time then a second later it returns the props data I want :)
return (
<div>
<div
className="row row-cols-1 row-cols-md-2 mx-auto"
style={{ maxWidth: 900 }}
>
{this.props.data.data.map((opportunity) => (
<div className="col mb-4">
<div>
<a href="#">
<img
className="rounded img-fluid shadow w-100 fit-cover"
src="assets/img/products/awsLogo.jpg"
style={{
height: 250,
}}
/>
</a>
<div className="py-4">
<span
className="badge mb-2"
style={{ margin: 2, backgroundColor: "#ff9900" }}
>
{opportunity.interview_type}
</span>
<span
className="badge bg mb-2"
style={{ margin: 2, backgroundColor: "#ff9900" }}
>
4
</span>
<span
className="badge bg mb-2"
style={{ margin: 2, backgroundColor: "#ff9900" }}
>
Reverse
</span>
</div>
</div>
</div>
))}
</div>
</div>
);
}
}
export default DashboardTable;
Dashboard (parent) This works. It passes the graphql data to the child
import React, { useEffect, useState } from "react";
import "bootstrap/js/src/collapse.js";
import DashboardTable from "../DashboardTable";
import { API } from "@aws-amplify/api";
import config from "../../aws-exports";
import * as queries from "../../graphql/queries";
export default function Dashboard() {
API.configure(config);
async function asyncCall() {
const gqlreturn = await API.graphql({
query: queries.listMockOppsTables,
});
// console.log(gqlreturn.data.listMockOppsTables); // result: { "data": { "listTodos": { "items": [/* ..... */] } } }
return gqlreturn;
}
// initialize with empty array
const [opportunityTable, changeOpportunityTable] = useState([]);
//console.log(opportunityTable); // this works! returns a promise
// call api to fetch data on mount
useEffect(() => {
const fetchData = async () => {
const response = await asyncCall();
changeOpportunityTable(response);
};
fetchData();
}, []);
return (
<div>
<section className="py-5 mt-5">
<div className="container py-5">
<h2 className="fw-bold text-center">
Your upcoming shadowing events
<br />
<br />
</h2>
<DashboardTable data={opportunityTable}></DashboardTable>
</div>
</section>
</div>
);
}
CodePudding user response:
You need to do this:
{ oppotrunityTable && opportynityTable.length ?
<DashboardTable data={opportunityTable}></DashboardTable>
: null
}
But you have an error not because of this, but because of the fact that your data is undefined!!! Check your data ))