You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js问题:如何确保router.push在所有API请求完成后触发

问题场景与需求

我有两个页面:

  • 页面1:包含待审批文档,设有「审批」按钮。点击按钮的onClick函数会通过Axios调用API,生成n个后续文档,这些文档创建后需要在页面2展示。
  • 页面2:使用getServerSideProps从数据库获取上述后续文档并渲染。

目前遇到的问题:页面1的审批按钮onClick函数中,router.push()会在所有API调用完成前触发,导致页面2的getServerSideProps无法获取到新生成的文档(必须手动硬刷新页面2才能看到)。

以下是当前的handleApproveClick函数代码:

const handleApproveClick = async () => {
    try {
      setLoading(true);
      const { data } = await axios.put(
        "https://blahblahblah.api.com/updateDocumentStatus/?docKey=sr&docType=stockrequests&status=Approved&docId=" +
          srId
      );

      const uniqueSuppliers = [
        ...new Set(
          stockRequest.sr_line_items.map(
            (supplier) => supplier.sr_line_item_supplier
          )
        ),
      ];
      console.log(uniqueSuppliers);

      const stockOrders = [];

      const createStockOrders = uniqueSuppliers
        .map(async (uniqueSupplier) => {
          const srFilterLineItems = await stockRequest.sr_line_items.filter(
            function (e) {
              return e.sr_line_item_supplier === uniqueSupplier;
            }
          );
          const soLineItems = await srFilterLineItems.map(
            (srFilterLineItem, index) => ({
              so_line_item_line_num: index + 1,
              so_line_item_sku_id: srFilterLineItem.sr_line_item_sku_id,
              so_line_item_description:
                srFilterLineItem.sr_line_item_description,
              so_line_item_uom: srFilterLineItem.sr_line_item_uom,
              so_line_item_uom_description:
                srFilterLineItem.sr_line_item_uom_description,
              so_line_item_price: srFilterLineItem.sr_line_item_price,
              so_line_item_quantity: srFilterLineItem.sr_line_item_quantity,
              so_line_item_total: srFilterLineItem.sr_line_item_total,
            })
          );
          console.log(soLineItems);
          const soCounter = await axios.put(
            "https://blahblahblah.api.com/counter/?counterName=so&venueId=RUL001"
          );

          setSending(true);

          const { data } = await axios.post(
            "https://blahblahblah.api.com/postDocument/?docType=stockorders",
            {
              so_id: `SO-RUL001-${soCounter.data.value.so_number}`,
              so_id_num: `${soCounter.data.value.so_number}`,
              so_sr_id: srId,
              so_total: round(
                soLineItems.reduce((a, c) => a + c.so_line_item_total, 0)
              ),
              so_date_created: new Date(),
              createdAt: new Date(),
              so_delivery_date: new Date(),
              so_venue: "RUL001",
              so_supplier: uniqueSupplier,
              so_supplier_id: "Update1",
              so_status: "Created",
              so_payment_terms: "30 days",
              so_line_items: soLineItems,
            },
            {
              headers: {
                "Access-Control-Allow-Origin": "http://localhost:3000/",
                "Content-Type": "application/json",
              },
            }
          );
          console.log(data);
          await axios.post("/api/emails/newstockordertosupplier", {
            ...data[0],
          });
        })
        router.push(`/my-approvals/stock-request/${srId}/stock-orders`);
    } catch (error) {
      console.log(error);
    }
  };

请问如何让router.push()仅在handleApproveClick中的所有API调用都完成后再触发?


解决方案

核心问题:uniqueSuppliers.map(async ...)会返回一个Promise数组,但你没有等待所有Promise执行完成就直接调用了router.push。同时代码里对同步的filter和map加了多余的await,可以去掉。

修改步骤:

  1. 用Promise.all()等待所有供应商对应的API调用全部完成
  2. 移除filter和map前多余的await(这两个是同步操作,不需要异步等待)
  3. 将router.push放在await Promise.all(createStockOrders)之后

修改后的代码:

const handleApproveClick = async () => {
    try {
      setLoading(true);
      const { data } = await axios.put(
        "https://blahblahblah.api.com/updateDocumentStatus/?docKey=sr&docType=stockrequests&status=Approved&docId=" +
          srId
      );

      const uniqueSuppliers = [
        ...new Set(
          stockRequest.sr_line_items.map(
            (supplier) => supplier.sr_line_item_supplier
          )
        ),
      ];
      console.log(uniqueSuppliers);

      const stockOrders = [];

      // 生成每个供应商对应的异步操作Promise数组
      const createStockOrders = uniqueSuppliers
        .map(async (uniqueSupplier) => {
          // filter是同步操作,不需要await
          const srFilterLineItems = stockRequest.sr_line_items.filter(
            (e) => e.sr_line_item_supplier === uniqueSupplier
          );
          // map是同步操作,不需要await
          const soLineItems = srFilterLineItems.map(
            (srFilterLineItem, index) => ({
              so_line_item_line_num: index + 1,
              so_line_item_sku_id: srFilterLineItem.sr_line_item_sku_id,
              so_line_item_description:
                srFilterLineItem.sr_line_item_description,
              so_line_item_uom: srFilterLineItem.sr_line_item_uom,
              so_line_item_uom_description:
                srFilterLineItem.sr_line_item_uom_description,
              so_line_item_price: srFilterLineItem.sr_line_item_price,
              so_line_item_quantity: srFilterLineItem.sr_line_item_quantity,
              so_line_item_total: srFilterLineItem.sr_line_item_total,
            })
          );
          console.log(soLineItems);
          const soCounter = await axios.put(
            "https://blahblahblah.api.com/counter/?counterName=so&venueId=RUL001"
          );

          setSending(true);

          const { data } = await axios.post(
            "https://blahblahblah.api.com/postDocument/?docType=stockorders",
            {
              so_id: `SO-RUL001-${soCounter.data.value.so_number}`,
              so_id_num: `${soCounter.data.value.so_number}`,
              so_sr_id: srId,
              so_total: round(
                soLineItems.reduce((a, c) => a + c.so_line_item_total, 0)
              ),
              so_date_created: new Date(),
              createdAt: new Date(),
              so_delivery_date: new Date(),
              so_venue: "RUL001",
              so_supplier: uniqueSupplier,
              so_supplier_id: "Update1",
              so_status: "Created",
              so_payment_terms: "30 days",
              so_line_items: soLineItems,
            },
            {
              headers: {
                "Access-Control-Allow-Origin": "http://localhost:3000/",
                "Content-Type": "application/json",
              },
            }
          );
          console.log(data);
          await axios.post("/api/emails/newstockordertosupplier", {
            ...data[0],
          });
        });

      // 等待所有异步操作完成后再跳转
      await Promise.all(createStockOrders);
      router.push(`/my-approvals/stock-request/${srId}/stock-orders`);
    } catch (error) {
      console.log(error);
    } finally {
      // 重置loading状态,避免异常时页面一直处于加载状态
      setLoading(false);
      setSending(false);
    }
  };

补充说明:

  • Promise.all()会等待数组中所有Promise都resolve后才继续执行后续代码,确保所有文档生成API都完成,数据库中已有数据后再跳转到页面2。
  • 移除多余的await可以避免不必要的异步等待,提升代码执行效率。
  • 在finally块中重置loading/sending状态,防止操作异常时页面一直处于加载状态。

内容的提问来源于stack exchange,提问作者Rich

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 20:45:34