I'm building a SPA based on WP API and want to render both posts and their featured images but they come in separate endpoints.
When rendering, React don't wait the request to resolve and get the error: "Uncaught Invariant Violation: Objects are not valid as a React child (found: [object Promise])."
Totally a beginner about Promise and Async/Await functions. Don't even know if I'm using it correctly.
import React, { Suspense, Component } from "react";
import { FontSizes, FontWeights, PrimaryButton, DefaultButton } from 'office-ui-fabric-react';
import axios from "axios";
import './Home.styl'
class Home extends Component {
constructor() {
super();
this.state = {
posts: []
}
}
componentWillMount() {
this.renderPosts();
}
renderPosts() {
axios.get('https://cors-anywhere.herokuapp.com/https://sextou.didiraja.net/wp-json/wp/v2/posts')
.then((response) => {
// console.log(response)
this.setState({
posts: response.data,
})
})
.catch((error) => console.log(error))
}
async getImg(mediaId) {
const getImg = axios
.get('https://cors-anywhere.herokuapp.com/https://sextou.didiraja.net/wp-json/wp/v2/media/17')
.then((response) => {
return {
url: response.data.source_url,
alt: response.data.alt_text,
}
})
const obj = getImg
return (
<img src={obj.url} />
)
}
render() {
const { posts } = this.state
return (
<span className="Home-route">
<h1 style={{textAlign: 'center'}}>Sextou!</h1>
<div className="events-wrapper">
{
posts.map((post, key) => {
return (
<div className="event-card" key={key}>
<img src={this.getImg()} />
<h2
className="event-title"
style={{ fontSize: FontSizes.size42, fontWeight: FontWeights.semibold }}
>
{post.title.rendered}
</h2>
{post.acf.event_date}
<span>{post.excerpt.rendered}</span>
<a href={post.acf.event_link} target="_blank">
<DefaultButton
text="Acesse o evento"
/>
</a>
<a href={post.acf.event_ticket} target="_blank">
<PrimaryButton
text="Comprar ingressos"
/>
</a>
</div>
)
})
}
</div>
</span>
);
}
}
export default Home;
You could fetch the images the same way as you fetched the posts:
Include them in your state
this.state = {
posts: [],
image: null
};
Call getImage in componentWillMount
componentWillMount() {
this.getPosts();
this.getImage();
}
setState when the promise resolves:
.then(response => {
this.setState(state => ({
...state,
image: {
url: response.data.source_url,
alt: response.data.alt_text
}
}));
});
Display a loading screen or a spinner until the image loads
render() {
const { posts, image } = this.state;
if (!image) {
return "Loading";
}
// ...
}
I would also advise using componentDidMount instead of componentWillMount, because componentWillMount is deprecated and is considered unsafe.
Here's a codesandbox example.
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