当我使用for循环时,不等待axios请求?

xtfmy6hx  于 2023-06-22  发布在  iOS
关注(0)|答案(3)|浏览(136)

我正在尝试通过productId从后端获取productInfo。我正在迭代productId并使用axios获取数据。但它每次编译只迭代一个元素。我如何在一次执行中迭代所有这些?

const useBasket = (location) => {
    const [products, setProducts] = useState([]);
    const [descriptions, setDescriptions] = useState([]); 
    console.log("ACCOUNT ID:", location.location.state.accountId);
    useEffect(() => {
        const getBasket = async () => {
            const basketResponse = await Axios.get("http://localhost:8084/accountId/" + location.location.state.accountId);
            setProducts(basketResponse.data.products);
        };
        const getProductInfo = async (props) => {
            console.log("INSIDE getProductInfo:",props);
            const productResponse = await Axios.get("http://localhost:8081/product/" + props).catch(err => console.log(err));
            setDescriptions([...descriptions,productResponse.data.description]);  
        }
        getBasket();
        for(let i = 0; i < products.length; i++){
            console.log("INSIDE FOR:",products[i]);
            getProductInfo(products[i]);
        } 
        
    }, []); 
    console.log("DESCRIPTIONS:",descriptions);
    return { descriptions }; 
};

我试着把for循环放在async函数里面。之后,我在for循环中调用了await函数。
我还把加载部分时,数据不完整,它不会返回。
但都没用。

tjrkku2a

tjrkku2a1#

状态更新是异步的,闭包捕获每个状态变量的当前值(在同一个闭包中不会改变)。您应该直接访问响应中的值,并使用await来确保在获取描述之前完成对产品的请求。
下面是实现它的一种方法:

const getBasket = async () => {
    const basketResponse = await Axios.get("http://localhost:8084/accountId/" + location.location.state.accountId);
    return basketResponse.data.products;
};
const getProductInfo = (props) => {
    return Axios.get("http://localhost:8081/product/" + props).then(r => r.data.description);
}
(async () => {
    const newProducts = await getBasket();
    setProducts(newProducts);
    const newDescriptions = await Promise.all(newProducts.map(getProductInfo));
    setDescriptions([...descriptions, ...newDescriptions]);
})();
9vw9lbht

9vw9lbht2#

getBasket是一个异步函数。执行不会等待它完成/返回才继续。这意味着你的for循环引用了一个不太可能被更新的产品状态变量。
有很多方法可以解决这个问题(假设您不能简单地修改产品获取以包括描述):

  • 您可以将getBasket Package 在promise中,并在迭代之前等待它。
  • 您可以在getBasket中合并getProductInfo函数并迭代basketResponse.data.products
  • 您可以将getProductInfo Package 在其自己的useEffect中,该useEffect在产品更新时执行,即
useEffect(() => {

   const getProductInfo = async (props) => {
      const productResponse = await Axios.get("http://localhost:8081/product/" + props).catch(err => console.log(err));
      setDescriptions((prev) => [...prev, productResponse.data.description]);  
  }

  for(let i = 0; i < products.length; i++){
      getProductInfo(products[i]);
  }
}, [products]);
yeotifhr

yeotifhr3#

这里有几件事可以改变,它们都归结为如何处理不会立即发生的事情,比如:
1.调用发送API请求的async函数(您确实要等待axios返回值,但不必等待整个async函数完成,因此for循环部分在请求完成之前就开始执行)
1.在setState之后使用state(这不是瞬时的,setState调用是批量处理并一起执行的,它是如此之快,以至于只有在编写在setState调用之后使用state的代码时,您才会注意到这种情况)
现在,可能有不同的方法来解决这个问题,但这里有一个变化最小的解决方案:

const useBasket = (location) => {
    const [products, setProducts] = useState([]);
    const [descriptions, setDescriptions] = useState([]);
    console.log("ACCOUNT ID:", location.location.state.accountId);
    
    const getBasket = async () => {
        const basketResponse = await Axios.get("http://localhost:8084/accountId/" + location.location.state.accountId);
        setProducts(basketResponse.data.products);
        return basketResponse.data.products;
    };
    const getProductInfo = async (props) => {
        console.log("INSIDE getProductInfo:", props);
        const productResponse = await Axios.get("http://localhost:8081/product/" + props).catch(err => console.log(err));
        setDescriptions([...descriptions, productResponse.data.description]);
    }

    useEffect(async () => {
        const prods = await getBasket();
        for (let i = 0; i < prods.length; i++) {
            console.log("INSIDE FOR:", prods[i]);
            getProductInfo(prods[i]);
        }

    }, []);

    console.log("DESCRIPTIONS:", descriptions);
    return { descriptions };
};
  1. getBasketgetProductInfo被移到useEffect之外(可选,为了可读性)
  2. getBasket还在完成时返回数据
    1.在getBasket调用之前添加了await
  3. for循环使用返回的列表而不是来自state的列表

相关问题