Here I have a useState for posts of my blog webapp. I am getting the posts from the mongoose back end which works fine. But the second I set the posts variable I get an infinite loop of rerendering.
Here is the app.jsx:
import React, {useState} from 'react';
import './App.css';
import Nav from './Navbar/NavBar.jsx';
import Content from "./content/Content"
import { getPosts } from "./api/post";
function App() {
const idList = ["631a58c165b3a10ac71497e1", "631a58fa65b3a10ac71497e3"];
const [posts, setPosts] = useState([]);
setPosts(async() => await getPosts(idList));
return (
<div>
hello
</div>
);
}
export default App;
Here is the axios part:
import axios from "axios";
const getPost = (id) => {
new Promise((resolve, reject) => {
const url = "/posts/" id
console.log(url)
axios.get(url)
.then(response => {
if (response.status === 200){
console.log("Succesfull call");
console.log(response.data);
resolve(response.data);
}
else if(response.status === 404){
reject(response);
}
})
.catch(err => {
console.log("Failed call");
reject(err);
})
});
};
const getPosts = async (idList) => {
var result = []
for(const id in idList){
try{
let post = await getPost(idList[id]);
result.push(post);
}catch(err){
console.log(err.message);
}
}
if (result.length === 0) throw {message: "No posts"};
else return result;
};
export {getPosts};
How can I run setPosts async so that the site wont refresh infinitely?
CodePudding user response:
You cannot pass a function returning a promise into the state setter. It must return the new state value directly.
You'll want to use an effect hook instead
useEffect(() => {
getPosts(idList).then(setPosts);
}, []); // empty dependency array means run once on mount
Given idList
appears constant, you should define it outside your component. Otherwise you'll need to work around its use as a dependency in the effect hook.
Your getPosts
function falls prey to the explicit promise construction anti-pattern. Since Axios already returns a promise, you don't need to make a new one.
You can also use Promise.allSettled() to make your requests in parallel.
const getPost = async (id) => (await axios.get(`/posts/${id}`)).data;
const getPosts = async (idList) => {
const results = (await Promise.allSettled(idList.map(getPost)))
.filter(({ status }) => status === "fulfilled")
.map(({ value }) => value);
if (results.length === 0) {
throw new Error("No posts");
}
return results;
};