开发者问题收集

Vue3-等待异步变量的悬念

2022-08-29
2155

我有以下两个组件(父组件和子组件)

.
├── Index.vue (Parent)
└── _GetShipment.vue (Child)

Index.vue 中,我尝试使用 Office.js 的 getAsync 获取电子邮件正文的内容:

<script>
import Shipment from './_GetShipment.vue';
import { ref, defineComponent, Suspense } from 'vue';


export default defineComponent({
    setup() {
        const shipments = ref([]);

        shipments.value = Office.context.mailbox.item.getRegExMatchesByName('ShipmentNumbers');

        if (!shipments.value) {
            Office.context.mailbox.item.body.getAsync(
                "text",
                function (result) {
                    if (result.status === Office.AsyncResultStatus.Succeeded) {
                        let matches = result.value.match(/S\w{3}\d{8,9}/ig);
                        if(matches){
                            shipments.value = matches;
                        }
                    }
                }
            );
        }

        return {
            shipments,
        }
    },
    components: {
        Shipment
    },
})
</script>

<template>
    <Suspense>
        <Shipment :id="shipments[0]" />
        <template #fallback>
            Loading...
        </template>
    </Suspense>
</template>

在子组件中,我使用 async setup 方法获取数据:

<script>
import { ref } from 'vue';

export default {
    props: ['id'],
    async setup(props) {
        const shipment = ref();
        await fetch(route('getShipment', {id : props.id}))
            .then(response => response.json())
            .then(data => shipment.value = data);
        return { shipment };

    }
};
</script>
<template>
    <div>
        <pre>{{ JSON.stringify(shipment, null, 2) }}</pre>
    </div>
</template>

导航到我的页面 Index.vue 时,会显示来自 SuspenseLoading... 后备消息,并且还会加载来自子组件的异步数据。 但是 ,控制台也会引发错误:

Uncaught (in promise) TypeError: Cannot read properties of undefined (reading '0')

我猜这是因为当加载 Index 时, shipments 变量未设置,但将在加载后立即设置。

如果我使用 v-if 呈现子组件,如下所示:

<template>
    <Suspense>
        <Shipment v-if="shipments" :id="shipments[0]" />
        <template #fallback>
            Loading...
        </template>
    </Suspense>
</template>

则不会显示后备加载消息。如何调用异步函数 ( getAsync() ) 并同时使用 Suspense 显示加载消息?

2个回答

Jaromanda X 的评论让我走上了正确的轨道:

not sure if :id="shipments?.[0]" would help

当组件加载时, shipments 变量为空 - 因为它正在等待异步函数 getAsync 完成。

将 Jaromanda X 的代码添加到父组件:

<Shipment :id="shipments?.[0]" />

然后在子组件中,我在 async setup(props) 方法下添加了这个:

while(!props.id){
   await new Promise(resolve => setTimeout(resolve, 100));
}

这消除了日志中的错误,加载消息成功显示,直到 fetch 完成。

oliverbj
2022-08-29

我建议您对 getAsync() 进行承诺,这样您就可以等待它,因为使用 callback 语法时,suspense 无法等待它。

<script>
import Shipment from './_GetShipment.vue';
import { ref, defineComponent, Suspense } from 'vue';


export default defineComponent({
    async setup() {
        const shipments = ref([]);

        const getAsyncMailbox = async () => {
           return new Promise((resolve, reject) => {
              Office.context.mailbox.item.body.getAsync(
                "text",
                function (result) {
                    if (result.status === Office.AsyncResultStatus.Succeeded) {
                        let matches = result.value.match(/S\w{3}\d{8,9}/ig);
                        if(matches){
                            shipments.value = matches;
                        }
                    }
                    resolve()
                }
            );

           })

        }

        shipments.value = Office.context.mailbox.item.getRegExMatchesByName('ShipmentNumbers');

        if (!shipments.value) {
            await getAsyncMailbox()
        }

        return {
            shipments,
        }
    },
    components: {
        Shipment
    },
})
</script>

<template>
    <Suspense>
        <Shipment :id="shipments[0]" />
        <template #fallback>
            Loading...
        </template>
    </Suspense>
</template>
Mina
2022-08-29