vuejs / core

đź–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

Home Page:https://vuejs.org/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Two-way binding can directly modify without emit 'update:model-value' event when using object to create ref() or reactive()

ningwang723 opened this issue · comments

Vue version

3.4.23

Link to minimal reproduction

https://play.vuejs.org/#eNqNUstu2zAQ/BWCFzuwK8dNT64c9IEcWqCtkRY9CSgUeeXQoUiCpFQHgv49S9KSpVgJciN3h8vZmanpZ6WiqgS6orHJNFOWGLCluk4EK5TUlnyVhSK5lgWZRAt3cfBJ1641pJllFcyJhrw5IgOEkERkUhhLMlkKS9YICeBp7Sury+ZiALmF3KPylwAbnjJxhFxiK14E1sgXLxYKxVMLeCMk9syrd4XcAl8ntP0goWQRAPe6PY1B/VdvBY/hmFClPQeGbl0fRWkat0XHnM5pK/JzTwhPxW5tzdCb5cCcpXfno1MjqOY//5vyElC1LeRMwA9Xmr5BvGWP/GlOtyqu0Jt+voc1SCFnu2hvpMBlap8IlKFQjIP+pSxDigldEd9xvZRz+f+7r1ldwrytZ/eQPYzU9+bgagndaDCgKyTX9Wyqd4B6u/bN759wwHPXROIlR/QrzVswkpeOY4B9KcUWafdwnu03bwUTuz/m5mBBmHYpR9QhG49PKBrjRH1p9RPdq+iDf5eI5pgG7+p4HPAhzkE/gt31yZGmM3yjpTJxr7UiqXhsrqcXGJTXQrBllT+Q+K60VgrMA8vdl48KZD7I1ppM5N0eMjvBfHzKOMseBqmJfNpnM+Q6ixdh3PPZwA2MvT17FdLXWxW1wkGLwLeXwkSggv8q0M4VFBCljd5f0eYJ4Aiuug==

Steps to reproduce

I show the code in playground.
when i create ref/reactive with Object and pass it to child component with v-model, it can directly modify without emit any event and it not trigger computed setter or watcher.

What is expected?

update value after emit 'update:model-value' event.

What is actually happening?

update value without emit 'update:model-value' event.

System Info

No response

Any additional comments?

No response

It seems that we can mutate a prop in the template, even though the Vue.js docs state there should be a warning if we try to mutate props in a child component. Interestingly, there doesn't appear to be a warning when a prop is mutated directly in the template.

Since the modelValue is also a prop, I believe this issue is closely related. I plan to open a pull request to add a warning when a prop is mutated in a template.

I've attached a link with a reproduction of the bug related to props. It seems the link to the documentation about readonly props may be lost during compilation.

I'm looking forward to your feedback and suggestions on this issue.

https://play.vuejs.org/#eNqtVE1v00AQ/SsjX+woxSYtp+BEfKgHkAoVIDhghFxnnDpd766863zI8n9ndu34I00LB272zNuZN2/ebuW8ldLflujMnVAlRSY1KNSlXEY8y6UoNLwXubyEtBA5uH5g/8wBtwNUBaZ1C2gSABFPBFcaElFyfcvijMMCCOe9nEQ8DJpO1IN+NOaSxRrpDyBsus3lInL6s5EDAaXDoMM6F45BnmMOLObrhVbjCWajCWZ2gtemf8MzFytk32NWIvFcYZpxvDEh7y9070qtBYftiywlxvogUaSjYgtwxd0GE+3SEG8SliUPBOwRvp1yOo2c5XQaBk29XooZlbbg0aFWD4CqGjar61ONtKLx0mztb5TgJFRld0PK5jJjWHyWOqPxI2cONmNyMWNi99HGdFHixTGe3GPycCa+UXsTi5zbAhUWWyLX5XRcrFE36euvn3BP312SiJeM0M8kv6ASrDQcG9i7kq+I9gBn2X6wa874+pu63mvk6jiUIWqQtcVHDi3diPrU6D3dK/+VPRfxunWadcx5q9FBqkP7aKxU9RupOzPdFkKqcJCaQ8wP9dKbkAmfM9gq29qP/2y1kdMGtZEpPHf20anGfYNRSSsqFDR8By6MeKugfTXOPDONatIINJbL++lK9xddwO6Slpoq/sj0vc0T2pvAYtks0BbwJRHl9hr8g6Tm+kjasqXeq9CNL6mDhCnMaPYb2xtMY6DH7FhxrOPjEieUTwrtKA5xkqBS5N5WA6reKrSLC05x7yBKgjJGkuExOBm/FU/o/nuLhbkNJDtZ2r+8cuo/RpQGhw==

The current behavior allows mutating a prop directly in the template, which could be considered a breaking change if we were to disallow it. Given that this is an existing functionality, we should carefully consider the implications before making any changes.

I'm looking forward to the team's suggestions on the best approach to handle this. We'll need to weigh the pros and cons of maintaining the current behavior versus introducing a warning or error when props are mutated in the template.

I'm updated the code to add an input element to handle the prop "modelValue" in v-model, the prop should be readonly, but it can mutate even it in none setter computed!

Playground

Reative object's properties are always mutable in Vue, and always have been. When the docs speak of "props are readonly", it means you can't assign to a prop and have that change propagate to the parent:

const props = defineProps({
  title: String,
  user: Object,
})

// this doesn't do anything, and this is what we mean when we say "props are readonly":
props.title = 'New Title'

// this doesn't mutate the prop `user`, it mutates a property `name` in the object provided through the prop. 
// This always was mutable in Vue and is *not* a bug.
props.user.name = 'Tom'

You can create explicitly readonly reactive data though if you need to: