Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

using useState async makes webapp render unlimited times

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:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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?

>Solution :

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;
};
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading