在阅读用Vue3编写的前端代码时,我偶然发现了一个迄今为止从未见过的构造,并且在理解它的工作原理时遇到了一些问题。其基本思想是将异步调用的结果(例如fetch
的JSON结果(分配给反应值。
我一直在做的方式显示在下面的代码中(Vue Playground(。setTimeout
模拟异步调用,返回Promise,然后通过设置反应变量msg
的then()
进行操作。
<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
就会更新(并返回默认值为one
的result
,因为setTimeout()
中的回调尚未发生(。一旦功能结束,就应该销毁它 - 。。。为什么我可以返回
result
(指针(并将其分配给msg.value
(字符串((它有效(
"one"
和"two"
(具有引号我的问题是:第二种方法正确吗?推荐?它确实简化了代码,因为所有异步部分都发生在函数中,但我从未见过这种方法
从技术上讲,您所称的async
函数不是async
函数。这是一个返回ref()
的函数立即,没有任何异步。
但该功能也有副作用(setTimeout
(。在将来的某个时刻,它会更新返回的ref
。因为你将结果分配给另一个ref
,所以当你修改返回的值时,你实际上修改了它被分配给的值
就你的观点而言,这是完全合法的。您可以将ref()
s分配给reactive()
的道具或另一个ref()
,如果/当您更新返回的ref
的值时,您传递给的值也将更新。
为了让我的观点更清楚,在您链接的示例中,msg.value
从x
开始,它立即被分配为ref('one')
的值,两秒钟后,内部ref()
的值被更改为'two'
此分配之后,如果选中msg.value
,则它是ref()
,不再是string
。但这对<template>
来说不是问题,因为它会自动打开任何嵌套的ref,直到它到达实际的.value
但是,请厌倦在控制器内部使用msg.value
(在分配之后(,因为您必须使用unref
才能获得string
值。
使用此技术可能会遇到的另一个潜在问题是watch
,因为msg
的值保持不变,因此在分配后将不再检测到更改:result
。为了解决这个问题,需要在观察者的选项中使用{ deep: true }
。