Subscribe on changes!

shallowRef as prop loses reactivity

avatar
Jul 15th 2022

Vue version

3.2.37

Link to minimal reproduction

https://sfc.vuejs.org/#eNp9U01v2kAQ/StTX2Ia8FbJoZJlEFHg0EsbRW1OewF7DE7s3e1+gCrk/97ZtQFDlBxAnpm3M2/evj1ED0olO4dRGmUm15WyYNA6NeOiapTUFh5lo6DUsoGbhPnAw29O5QOY7aqu5f4ZyzFYXW02qMP3fmXz7bIsMbfQ9h26o1zkUhgLuTNWNi+r2iFMB33iAxcAuXTCok7hGxftyJ8qnchtJQVUItfYoLDxqIOeGyW78N8fvr315TOreICkli0XGevWpoUpsNioemWRIoBMaZwdDhc02zZjPh3qQZrUorFTHg1QPGIdYO2sJbrzvK7yN8KcePMoAAB+nDIez7oDVMvYiUo0jjqtJ81KJa9GCrqssDY1DAXDoxRCxudIYx/zaGutMiljTqi3DSnSsDnVmCZlqgYnhWzm98ldcv+dFZWxw3yCppmstdwb1DSRR+NBc0bJHeqJRlGgRv3psCvsxcCr2ruhfibdUEsCHH33sU3pmgjjLBafOY9W6L2ntFSGXFdgWQl88lFnO3+dJzXtP4Up/Fq/UqteA41/XaWxSMlWpHTPkcx07l1It669pY+U4ngE01k3M/EDjv6Er3AXrD2g3IMDA8bg5/Jl+Qx/nhYPv5eLL93DEEbWmNRyE79v6W1Nvw99zW3mZfOrPB5fGJn8glVLK3nAIiwS6v1OXYXewJVH2//vjH95

Steps to reproduce

  1. Create a shallowRef with object value
  2. Pass the ref as a component prop.
  3. Print the value of the prop in the template.
  4. Update a ref object value property.
  5. Call triggerRef on the created ref.

What is expected?

It is expected that the changes will also be sent to the component without reassigning the value property of the ref

What is actually happening?

Changes are not reflected in the component receiving the ref via prop.

System Info

System:
    OS: Linux 5.15 Manjaro Linux
    CPU: (16) x64 AMD Ryzen 7 5700G with Radeon Graphics
    Memory: 4.24 GB / 13.45 GB
    Container: Yes
    Shell: 5.9 - /usr/bin/zsh
  Binaries:
    Node: 14.19.3 - ~/.nvm/versions/node/v14.19.3/bin/node
    Yarn: 1.22.19 - ~/.yarn/bin/yarn
    npm: 6.14.17 - ~/.nvm/versions/node/v14.19.3/bin/npm
  Browsers:
    Brave Browser: 103.1.40.107
    Chromium: 103.0.5060.114
    Firefox: 102.0

Any additional comments?

I'm creating components to work with large amounts of data and I need to manually control when a ref should be triggered to have better performance.

avatar
Jul 15th 2022

the content of the shallow ref is non-reactive. You pass the content to the child. So you pass a non-reactive content to the child. so you can't watch that object.

avatar
Nov 23rd 2022

@LinusBorg I'm running into this issue and your comment is somewhat confusing, could you clarify how the following point works:

let ganttBars = shallowRef<GanttEntry[]>([]);
ganttBars.value = [...ganttBars.value]; // Does trigger component->watch(data)
triggerRef(ganttBars) // Does not trigger component->watch(data)

<template>
   <Timeline :data="ganttBars"/>
</template>

Why does a root mutation trigger watch (or a re-render) while triggerRef does not? (vue@^3.2.45 btw) Am I misunderstanding what triggerRef does?

avatar
Nov 23rd 2022

triggerRef will make the parent re-render, but since the ref still contains the same plain array, no prop has changed for <Timeline>, so that component will not re-render.

avatar
Nov 23rd 2022

Ah I see that makes sense (properties are compared by using standard js cmp I guess), thank you for the quick clarification

avatar
Nov 23rd 2022

@LinusBorg I'm running into this issue and your comment is somewhat confusing, could you clarify how the following point works:

let ganttBars = shallowRef<GanttEntry[]>([]);
ganttBars.value = [...ganttBars.value]; // Does trigger component->watch(data)
triggerRef(ganttBars) // Does not trigger component->watch(data)

<template>
   <Timeline :data="ganttBars"/>
</template>

Why does a root mutation trigger watch (or a re-render) while triggerRef does not? (vue@^3.2.45 btw) Am I misunderstanding what triggerRef does?

In the demo customValue.value is not reactive, the NotShallowRef.value is reactive. this is the ref and shallowRef's different. playground demo

shallowRef