大佬们, vue3 新人求教,就没有办法对 ref 包装的 obj 进行解构吗

5 天前
 zhengfan2016

如题,demo 代码如下,模拟读取后端 api 返回: 使用 data.value 可以获取到数据,但是使用 list?.value 获取不到数据,问了 gpt 也问不出如何使用 const {data:list} 开头的代码进行解构,难道 ref 就没法解构吗

1549 次点击
所在节点    Vue.js
21 条回复
wunonglin
4 天前
你不如把 data 和 list 打印出来比比看,就知道怎么回事了
sjhhjx0122
4 天前
你的 list 只拿到初始默认 data 的 undefined ,你如果想让 list 时刻随着 data 响应应该用计算属性
Track13
4 天前
先学一下 js 吧,const {data:list} 这一行执行的时候 你的 ref 还是 undefined 。
heishu
4 天前
我猜你找的是 computed
dadaji
4 天前
为什么我看见 any 想喷人
shintendo
4 天前
鉴定为 react 写多了
zhhbstudio
4 天前
toRef 也可以解决
const list = toRef(data, 'data')

toRefs 主要是 reactive 的属性转 ref ,这个可以直接解构
tyrone2333
4 天前
@dadaji anyscript 怎么你了😋
zhengfan2016
4 天前
@shintendo 确实,react 写多了,看到 vue 一长串可选链就想改成 react 的解构写法,之前 vue 转过来的同事就很喜欢写一长串的可选链
zhengfan2016
4 天前
@heishu computed 不行啊😭,gpt 提示 computed 返回 ref 不可解构
zhengfan2016
4 天前
@zhhbstudio 这个一行只能一个变量,我想找能在一行解构多个变量并保持响应式的写法😂,

类似 react 这样的:const {code,data,message} = xxx || {} 这样,这样一行就定义三个变量,

而不是 vue
const code = data?.value?.code;
const list= data?.value?.data ;
const message = data?.value?.message;

这样的写法,这样写比较啰嗦。
zhhbstudio
3 天前
@zhengfan2016

const data = reactive({list: null, code: null, message: null})

接口返回后挨个赋值

用的时候直接 data.code data.list

也能转 ref ,但不推荐 const {code ,list} = toRefs ( data ) code.value

每个框架有自己的写法习惯,你非要把 react 的拿过来会很不舒服的

找俩 star 多的 vue3 开源看看他们怎么处理的接口返回吧
ooo4
2 天前
试试这个

const data = reactive({ code: null, data: [] })
onMounted(() => {
setTimeout(() => {
Object.assign(data, { code: 0, data: [666, 777, 888] })
}, 1000)
})

function useFoo(state) {
const res = {}
watchEffect(() => {
for (let key in state) {
res[key] = toRef(state, key)
}
})
return res
}

const { data: list } = useFoo(data)

watchEffect(() => {
console.log('data', data)
console.log('list', list)
})
ooo4
2 天前
@ooo4
不需要这么麻烦
```
import { reactive, watchEffect, onMounted, toRefs } from 'vue';
const data = reactive({ code: null, data: [] })
onMounted(() => {
setTimeout(() => {
Object.assign(data, { code: 0, data: [666, 777, 888] })
}, 1000)
})


const { data: list } = toRefs(data)
watchEffect(() => {
console.log('list', list.value.length)
})
```
ooo4
2 天前
toRefs 的参数必须是一个对象才行,而且必须还要存在属性,因为它要把对应的属性值变成 ref 。
而现在使用的是 ref 包裹数据,那么也应该是`const {data:list} = toRefs(data.value)`才行,让 list 变成了响应式数据,
但是是通过`data.value = { code: 0, data: [666, 777, 888] }`改变数据,也只是改变了 data(ref),list 并没有改变,所以 list 还是以前的数据,如果这样`Object.assign(data.value, { code: 0, data: [666, 777, 888] })`修改数据应该可以

看错了 [如果对 ref 包装的 obj 进行解构]
```
import { reactive, watchEffect, onMounted, toRefs, ref } from 'vue';
const data = ref({ code: null, data: [] })
onMounted(() => {
setTimeout(() => {
Object.assign(data.value, { code: 0, data: [666, 777, 888] })
}, 1000)
})

debugger
const { data: list } = toRefs(data.value)
watchEffect(() => {
console.log('list', list.value)
})
```
Outshine
1 天前
看了代码,我寻思 `react` 里你这代码也不能这样用啊。

你这 `list` 并不是响应式数据,因为此时 `data` 为 undefined ,那么就会结构后面的 {},{} 里面没有 `data` 这个键(实际里面有没有这个键 list 都不是响应式)

```javascript
const { data: list } = toRefs<any>(data) || {}
```
zhengfan2016
1 天前
@Outshine react 为什么不能这样用,react 只要你的函数组件的 props 变了,整个组件就会 rerender 。


```
const data = useQuery()
const {list} = data || {}

```

还有就是如果你组件内在 data 这里触发了重渲染,那么下面的所有的每一行代码都会触发重新计算,这也是网传所谓的 react 性能比 vue 差的缘故,但是懂的 react 前端会把组件拆的足够细,尽量让触发副作用重新渲染的时候的受影响范围足够的小,这也是 react 的 jsx 能放多个组件,而 vue 的 sfc 只能放一个组件的原因之一。

至于 react 加{}只是为了防止解构 undefined 报错的,就和 vue 的 data?.value?.aaaa?.bbbb 加可选链是一样的
zhengfan2016
1 天前
@ooo4 #15 感谢,试过了代码确实能正常运行,但我发现了两个问题,一个是 reactive 默认值必须填入{ code: null, data: [] },哪怕是{ code: undefined, data: undefined}也是 ok 。而去掉其中任何一个 key 或者把 reactive 置为 undefined 都会导致不能正常运行。

另一个就是 Object.assign(data.value, { code: 0, data: [666, 777, 888] })这行必须要有,没有这行也会导致代码不能正常运行。这行确实没看懂,我看 mdn 的介绍和用 data.value 修改效果理论上应该是一样的
ooo4
1 天前
@zhengfan2016 因为 setup 函数不是副作用,所以不会重新执行,那么 toRefs 的数据在没有其他副作用的情况下,是不会改变的
如果保持你的代码,那么只能改渲染函数了,让他尽量的像 react
```
// Comp.js 不是 sfc
import { watchEffect, onMounted, toRefs, ref } from 'vue';

export default {
setup() {
let data = ref()
onMounted(() => {
setTimeout(() => {
data.value = { code: 0, data: [666, 777, 888] }
}, 1000)
})

return () => {
// 渲染函数 这是副作用,当响应式数据改变了,就会重新执行
const { data: list } = toRefs(data.value) || {}
watchEffect(() => {
console.log('list', list?.value)
})
// jsx
return 1
}
}
}
```
jiangzm
1 天前
用 reactive 定义, 用 toRefs 结构。 这么简单为啥讨论这么多

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1101860

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX