Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Setting a reactive object on a shallowReactive map "unwraps" the nested refs in the reactive object #8501

Closed
Fuzzyma opened this issue Jun 5, 2023 · 4 comments · Fixed by #8503
Labels
🔨 p3-minor-bug Priority 3: this fixes a bug, but is an edge case that only affects very specific usage. 🐞 bug Something isn't working scope: reactivity

Comments

@Fuzzyma
Copy link

Fuzzyma commented Jun 5, 2023

Vue version

@a95e612 (current commit after 3.3.4)

Link to minimal reproduction

https://play.vuejs.org/#eNqNkE1ugzAQha8y8sZGoiCyrEikHqCbbuMsEDEEyX/ChqiyfPeOCaJNk0U2lmfe957HE8iHtcU8CfJOateOg/XghJ/sgetBWTN6CDCKLsejaf0wixzcpZHSXL/WBkToRqOAYgrlGoDr1mjnQbke9snMaHN2NNv635s1ybcrC4jHJ8xnYxH79ybT4gqosOORdsZUNP/jOJ0yzOH6LqPAX7HE7u7YBUxPGikKaXr2KxU40DrPo5gS+zWxotnL7G5j6/K2blw0Fl4oKxsvsAKoL9UhhGV/MdYlVkt30HbyML8pcxZyzwnqnKBUl5sbSPwBWo+lvA==

Steps to reproduce

Open the example. In the console you see the message printed twice but once you see the internal ref printed.

The issue only shows itself when using "set" on a shallow Reactive map (foo2)
If you initialize the map with the same value, it is correct (foo1)

What is expected?

The behavior should be consistent.
Either the shallowReactive map should ALWAYS resolves the ref or never.

Imo, the reactive object in the shallowReactive should behave as normal. Hence, in my example, it should always resolve the ref correctly (because thats what the reactive is for)

What is actually happening?

The behavior is inconsistent depending on if the map is initialized with the value or later set

System Info

System:
    OS: Linux 5.15 Ubuntu 22.04.1 LTS 22.04.1 LTS (Jammy Jellyfish)
    CPU: (16) x64 AMD Ryzen 7 PRO 6850HS with Radeon Graphics
    Memory: 10.51 GB / 15.28 GB
    Container: Yes
    Shell: 5.1.16 - /bin/bash
  Binaries:
    Node: 19.8.1 - ~/.nvm/versions/node/v19.8.1/bin/node
    Yarn: 3.3.0 - /usr/bin/yarn
    npm: 8.19.4 - ~/repos/packmatic/node_modules/.bin/npm
  Browsers:
    Chrome: 114.0.5735.90

Any additional comments?

I am aware that you shouldnt have reactive objects in shallowReactive ones :D

@LinusBorg LinusBorg added 🐞 bug Something isn't working scope: reactivity labels Jun 5, 2023
@shaileshnighojkar
Copy link

@Fuzzyma @LinusBorg

As per documentation - https://vuejs.org/api/reactivity-advanced.html#shallowreactive

Screenshot




Since they stored are as-is, I tried to log the Map which is passed to shallowReactive as well. The returned values are same ie, as-is (not unwrapped)

const msg = ref('ads')
const myReactive = reactive({msg})
const myMap = new Map([['foo1', myReactive]])
const myReactiveMap = shallowReactive(myMap)
const log = key => console.log(key, myMap.get(key).msg, myReactiveMap.get(key).msg)

log('foo1') // foo1 ads ads

myReactiveMap.set('foo2', myReactive)
log('foo2') // foo2 RefImpl RefImpl
  
myMap.set('foo3', myReactive)
log('foo3') // foo3 ads ads

Link: https://play.vuejs.org/#eNp1kUEOgjAQRa8yYdOaEIy6M2riAdy4tS4IFiRC29ACIYS7OwNKgOimaf+8P/PTab2zMUFVSm/vHWxUpMaBla40J6HS3OjCQQuFjH08wsillfTBPsMs0/X1I0AHcaFzYNiFCSVUpJV1kNsEjmTlLHxYthr1ZjRSebjyFvFuwlxCg2Ula8Abv91YrPWG+RP3/f6j5WBbBOR9u5HONAV7yQaOJyBJZzJAkaNEA5ANEunouQow1nTosoZNhSLvkK9/zmn8zL64nYVH8OvakguAfFN+94/fEX9YD7vCLQnldW+FkZ/Y

It looks like shallowReactive is working as per the documentation.

Also, when I change shallowReactive to reactive, I am getting consistent 'ads' console log for myReactiveMap.get(key).msg.

@LinusBorg
Copy link
Member

LinusBorg commented Jun 5, 2023

In my understanding values being stored "as-is" means they are left untouched.

So when you set as a value on the map with a reactive proxy, that would stay a reactive proxy - and that reactive proxy would unwrap nested refs. just like it does for foo1, which is stored as the reactive proxy in the map.

The problem here is that shallowReactive seems to apply a toRaw when setting values, but not when initializing the map with predefined values. Which is an inconsistent behavior.

@Fuzzyma
Copy link
Author

Fuzzyma commented Jun 6, 2023

@shaileshnighojkar I disagree. as-is means, that nothing is changed in whatever object you pass to shallowReactive.
Since you pass a reactive object, that exposes every property (and doesnt expose refs), shallowReactive should leave it untouched and just also return every property as before. A reactive object should behave like a transparent proxy. From the shallowReactive functions point of view, it is just a plain object

ref values will not be automatically unwrapped

In a sense the opposite happens because they are going from unwrapped to wrapped

@LinusBorg what do you think which behavior makes more sense?

@LinusBorg
Copy link
Member

I think my previous reply is pretty much in sync with your understanding

@sxzz sxzz added the 🔨 p3-minor-bug Priority 3: this fixes a bug, but is an edge case that only affects very specific usage. label Aug 13, 2023
@github-actions github-actions bot locked and limited conversation to collaborators Aug 1, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
🔨 p3-minor-bug Priority 3: this fixes a bug, but is an edge case that only affects very specific usage. 🐞 bug Something isn't working scope: reactivity
Projects
None yet
4 participants