vuejs / core

🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
https://vuejs.org/
MIT License
47.79k stars 8.35k forks source link

`triggerRef` fails when target is an array #12427

Open ilyary opened 1 week ago

ilyary commented 1 week ago

Vue version

3.5.6

Link to minimal reproduction

https://play.vuejs.org/#eNqVU8tu2zAQ/JUtL5IBVW7QnlzZSFsYaHtIi6RAD2UPsrySlVIkwYdiQNC/d0klthMEDnIRxJnZ4SyXHNgnrfPeI1uwwlam1Q4sOq9XXLadVsbBAAbrjD5l5doeM3DqOgB3pat267rGyhFm2qZBQ8QItVEdJOSZcMllpaR10NkGlsEoTb6iEAp+KyO2b5LZUVIr00XNtE86gLdoFrQ/dmUrFvAnKS/LvFJdkkGyudzE378wwjj7eLSJ4ivfbWIaMoxx0+CeB8M8CjJ4F4pOekjTGSxXMHAJEJyUwFyoJn3sl/el8BhK7zc9Nv5EOdGPUt2QWDZnUyUXyWtyHRxfzHVQBrqYT6OmIdPCYadF6ZBWAMXuYjUMcV7jWMxpFdFWau+gf9upLYolZ8RzBnMii/lJPcuYs5Sybpv81ipJtyoG54xmpVuB5od2LXXBGQ02MIEr6ULcfY+YMx6zB7zaYfXvGfzW7gPG2U+DdHY9cnbgXGkadBO9vrnCPf0fSErvBanPkNdIJ+xDxkn22cstxT7RxbTf4tugE/1l13uH0j40FYIG5Rj1nNEz+HKm9WPc9/mHWEcTZON/Pog4cQ==

Steps to reproduce

const form = reactive({ user: { email: ['a@a.com', 'b@b.com'] } });

const emailNumberRef = toRef(form.user.email, 0);
watchEffect(() => {
  console.log(emailNumberRef.value);
});

triggerRef(emailNumberRef); // <-- FAILS
/*
@vue/reactivity/dist/reactivity.cjs.js:1487
    ref2.dep.trigger({
             ^

TypeError: Cannot read properties of undefined (reading 'trigger')
*/

const emailStringRef = toRef(form.user.email, '1'); // <-- TS is not happy
watchEffect(() => {
  console.log(emailStringRef.value);
});

triggerRef(emailStringRef); // <-- WORKS FINE

On The SFC playground it fails silently. No effect is called for number prop, but it works fine for string prop

What is expected?

triggerRef triggers effects for a reference with an integer key

What is actually happening?

triggerRef fails on a reference with an integer key

System Info

System:
    OS: macOS 14.4.1
    CPU: (8) arm64 Apple M1
    Memory: 66.09 MB / 16.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 20.12.2 - ~/.nvm/versions/node/v20.12.2/bin/node
    npm: 10.5.0 - ~/.nvm/versions/node/v20.12.2/bin/npm
    pnpm: 9.10.0 - ~/.nvm/versions/node/v20.12.2/bin/pnpm
  Browsers:
    Chrome: 130.0.6723.117
    Safari: 17.4.1

Any additional comments?

it happens because Proxy index gets converted to string.

So, here https://github.com/vuejs/core/blob/14f6917c3c47b9e27298c741e0e3f76c89868482/packages/reactivity/src/baseHandlers.ts#L113 the property starts being tracked with a string key but later on is referenced with a number key https://github.com/vuejs/core/blob/14f6917c3c47b9e27298c741e0e3f76c89868482/packages/reactivity/src/dep.ts#L389

Consider converting string key to number for arrays when tracking

edison1105 commented 1 week ago

~~It works fine with v3.5.13, see Playground I think only the ts error should be fixed.~~

ilyary commented 1 week ago

@edison1105, no, it's not

You may observe in the console one output from number and two outputs from string. it should be two outputs from number as well. it just fails silently((

[@vue/repl] successfully compiled 1 module. VM51 about:srcdoc:159 number a@a.com VM51 about:srcdoc:159 b@b.com VM51 about:srcdoc:159 b@b.com

Pls, review again

ilyary commented 1 week ago
@vue/reactivity/dist/reactivity.cjs.js:1487
    ref2.dep.trigger({
             ^

TypeError: Cannot read properties of undefined (reading 'trigger')

this error is printed in Node.js , when executing this piece of code in shell

Browser is silent

ilyary commented 1 week ago

it's not only TS.

the basic cause is how Proxy treats properties e.g. Proxy index gets converted to string