【问题标题】:Preventing a setState from running until network request is complete在网络请求完成之前阻止 setState 运行
【发布时间】:2022-11-28 00:05:23
【问题描述】:

在我的 React 应用程序的上下文文件中,我有以下功能:

const fetchAll = (userId) => {

        try {
            fetchDetails(userId)
            // To be clear... There's multiple functions here, i.e:
            // fetchContact(userId)

        } catch (err) {
            console.log(err)
        } 

        setPending(false)

    }

我已经删除了一些功能 - 但该功能的主要前提是将多个承诺组合在一起,并且在这些完成之前,显示一个“待定”组件。

如果“待定”状态设置为 true,则会显示此待定组件:

const [pending, setPending] = useState(true)

但是,目前发生的情况是尝试尝试,但同时执行了 setPending。

我认为解决这个问题的一种方法是在我的 try/catch 结束时使用“finally”调用,但它仍然同时执行。像这样:

const fetchAll = (userId) => {

        try {
            fetchDetails(userId)
        } catch (err) {
            console.log(err)
        } finally {
            setPending(false)
        }

    }

我不希望我的任何函数异步运行:我希望它们全部同时执行,以防止同时出现多个网络请求的瀑布效应。

作为参考,我个人的“获取”函数调用端点并根据响应设置状态数据:

const fetchDetails = (userId) => {
        axios.post("/api/fetch/fetchDetails", {
            id: userId
        })
        .then((response) => {
            console.log(response.data)
            setName(response.data.name)
            setPreviewPhoto(response.data.profile_picture_url)
            setPhotoName(response.data.profile_picture_name)
            setPhotoFile(response.data.profile_picture_url)
        })
    }

有没有人对我如何使这项工作有任何建议?

【问题讨论】:

    标签: reactjs


    【解决方案1】:

    fetchDetails返回一个promise,需要使用async/await

    const fetchAll = async (userId) => {
    
        try {
            await fetchDetails(userId)
        } catch (err) {
            console.log(err)
        } finally {
            setPending(false)
        }
    
    }
    

    【讨论】:

    • 不,这是错误的。就像我说的,我不想用我的函数创建瀑布效果。我在尝试中执行了多个函数,因此它们都需要同时运行。
    • 不 。 Axio 调用是异步的。你需要等到它被解决否则javascript tread将在解决承诺之前继续执行
    • 使用 Promise.all 可以在一定程度上解决它,但如果可以在一次调用中从服务器获取所有数据会更好
    • 如果有多个 API 调用,则承诺所有调用都是合适的。但是因为这里只有一个 API 调用,不需要全部使用
    • 我在问题中说过有多个 API 调用 :)
    【解决方案2】:

    根据您的用例,您可以使用 Promise.all()Promise.allSettled() 进行多个异步调用。

    setPending(true)
    try {
      await Promise.all([() => fetchAll(1), () => fetchAll(2)])
    } finally {
      setPending(false)
    }
    

    这将等待所有呼叫完成(或一个失败)

    【讨论】:

      【解决方案3】:

      假设您有 2 个 API 调用:fetchAll('123') 和 fetchAll('321');

      为了等待你所有的请求然后更新你的状态,你应该像这样使用Promise.all

      Promise.all([fetchAll('123'), fetchAll('321')]).then((responses) => {
        setPending(false)
      }
      

      【讨论】:

        最近更新 更多