我真的可以返回一个反应变量并让它异步更新它的值吗



在阅读用Vue3编写的前端代码时,我偶然发现了一个迄今为止从未见过的构造,并且在理解它的工作原理时遇到了一些问题。其基本思想是将异步调用的结果(例如fetch的JSON结果(分配给反应值。

我一直在做的方式显示在下面的代码中(Vue Playground(。setTimeout模拟异步调用,返回Promise,然后通过设置反应变量msgthen()进行操作。

<script setup>
import { ref } from 'vue'
const msg = ref('one')
const asyncCall = () => new Promise((resolve, reject) => {
setTimeout(() => {
resolve("two");
}, 2000);
})
asyncCall().then(r => msg.value = r)
</script>
<template>
<h1>{{ msg }}</h1>
</template>

我偶然发现的代码(Vue Playground(采用了不同的方法:它在函数中创建一个本地反应变量,进行异步调用,并在解析时设置该本地ref变量的值。然后返回(这是视觉序列,执行不同,请参阅下面的注释(

<script setup>
import { ref } from 'vue'
const msg = ref('x')
const asyncCall = () => {
const result = ref('one')
setTimeout(() => {
result.value = 'two'
}, 2000)
return result
}
msg.value = asyncCall()
</script>
<template>
<h1>{{ msg }}</h1>
</template>

它也起作用,但我不明白:

  • 。。。为什么一旦我们离开asyncCall,局部变量result就会更新(并返回默认值为oneresult,因为setTimeout()中的回调尚未发生(。一旦功能结束,就应该销毁它
  • 。。。为什么我可以返回result(指针(并将其分配给msg.value(字符串((它有效(
  • 。。。为什么显示的值("one""two"(具有引号转变为自己的问题

我的问题是:第二种方法正确吗?推荐?它确实简化了代码,因为所有异步部分都发生在函数中,但我从未见过这种方法

从技术上讲,您所称的async函数不是async函数。这是一个返回ref()的函数立即,没有任何异步。

但该功能也有副作用(setTimeout(。在将来的某个时刻,它会更新返回的ref。因为你将结果分配给另一个ref,所以当你修改返回的值时,你实际上修改了它被分配给的值

就你的观点而言,这是完全合法的。您可以将ref()s分配给reactive()的道具或另一个ref(),如果/当您更新返回的ref的值时,您传递给的值也将更新。


为了让我的观点更清楚,在您链接的示例中,msg.valuex开始,它立即被分配为ref('one')的值,两秒钟后,内部ref()的值被更改为'two'
此分配之后,如果选中msg.value,则它是ref(),不再是string。但这对<template>来说不是问题,因为它会自动打开任何嵌套的ref,直到它到达实际的.value
但是,请厌倦在控制器内部使用msg.value(在分配之后(,因为您必须使用unref才能获得string值。

使用此技术可能会遇到的另一个潜在问题是watch,因为msg的值保持不变,因此在分配后将不再检测到更改:result。为了解决这个问题,需要在观察者的选项中使用{ deep: true }

最新更新