大佬们, vue3 新人求教,就没有办法对 ref 包装的 obj 进行解构吗 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
zhengfan2016
V2EX    Vue.js

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

  •  3
     
  •   zhengfan2016 281 天前 2859 次点击
    这是一个创建于 281 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

    21 条回复    2025-01-06 11:36:06 +08:00
    shakaraka
        1
    shakaraka  
    PRO
       280 天前 via iPhone
    你不如把 data 和 list 打印出来比比看,就知道怎么回事了
    linkopeneyes
        2
    linkopeneyes  
       280 天前   2
    你的 list 只拿到初始默认 data 的 undefined ,你如果想让 list 时刻随着 data 响应应该用计算属性
    bgm004
        3
    bgm004  
       280 天前
    先学一下 js 吧,const {data:list} 这一行执行的时候 你的 ref 还是 undefined 。
    heishu
        4
    heishu  
      &nsp;280 天前
    我猜你找的是 computed
    dadaji
        5
    dadaji  
       280 天前 via iPhone
    为什么我看见 any 想喷人
    shintendo
        6
    shintendo  
       280 天前
    鉴定为 react 写多了
    zhhbstudio
        7
    zhhbstudio  
       280 天前
    toRef 也可以解决
    const list = toRef(data, 'data')

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

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

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

    这样的写法,这样写比较嗦。
    zhhbstudio
        12
    zhhbstudio  
       279 天前
    @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
        13
    ooo4  
       278 天前
    试试这个

    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
        14
    ooo4  
       278 天前
    @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
        15
    ooo4  
       278 天前   1
    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
        16
    Outshine  
       278 天前
    看了代码,我寻思 `react` 里你这代码也不能这样用啊。

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

    ```Javascript
    const { data: list } = toRefs<any>(data) || {}
    ```
    zhengfan2016
        17
    OP
       277 天前
    @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
        18
    zhengfan2016  
    OP
       277 天前
    @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
        19
    ooo4  
       277 天前
    @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
        20
    jiangzm  
       277 天前
    用 reactive 定义, 用 toRefs 结构。 这么简单为啥讨论这么多
    Outshine
        21
    Outshine  
       276 天前
    @zhengfan2016 #17 不是,你这段代码在 react 里相当于 const { value } = useRef(undefined) || {} 而不是你举例这个。

    ---

    另外,解决方案参考 #20 @jiangzm 的,vue 文档里也讲过这个。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     857 人在线   最高记录 6679     &bsp; Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 31ms UTC 21:40 PVG 05:40 LAX 14:40 JFK 17:40
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86