Subscribe on changes!

In a special case, the attribute binding will fail.

avatar
Jan 5th 2022

Version

3.2.26

Reproduction link

sfc.vuejs.org/

Steps to reproduce

As a comparison, enter the following two sets of characters in the input box.

  1. Enter '1', '2', '3', '4' in order. They are completely different characters.
  2. Enter 'a', 'a', 'a', 'a' in order. They are completely same characters.

What is expected?

In the second case, there should always be a single "a" in the input box.

What is actually happening?

In the second case, Vue does not do anything. The input box behaves just like its default behavior.


Here is my speculation:

Normally, the "value" of the input box is the same as the "text". Therefore, for efficiency, when the value assigned to "text" is the same as the previous one, it is not re-rendered.

However, in the callback of the "input" event, the "value" is the new content entered by the user, and the "text" is the old content that has not been changed. If you try to revert the input box to the old content (by changing the "text"), it will be ignored by Vue.

This behavior is also present on other forms.

(This issue was modified from machine translation. If something is not clear, please feel free to ask.)

avatar
Jan 5th 2022

A similar problem exists in vue 2, but I haven't tested the version specifically.

avatar
Jan 5th 2022

I believe that this is the same case as https://github.com/vuejs/vue/issues/7506#issuecomment-372139382 and it always worked like that

When you type "a", component re-renders because previous value of text was "3", but when you type the same letter for the second time, component won't update because value has not changed. You can fix this by setting a new value of the input field in your @input handler.

Updated demo

avatar
Jan 7th 2022

I think the reason of this bug is the hasChanged function in here: https://github.com/vuejs/vue-next/blob/master/packages/reactivity/src/baseHandlers.ts#L170

In this case, the text you input is same as you input before, so it will not trigger effect or update component.

If we remove the hasChanged function, this bug will be fixed. But this comes with additional performance overhead.

Is there a better way to fix it?

avatar
Jan 19th 2022

I've come up with an argument for this behavior of Vue. This might be an okay explanation:

Vue always assumes that the bound data is the same as the real value of the form. The advantage of this is that when the bound data is assigned by its old value, Vue can ignore the assignment to optimize performance.

However, this assumption is broken in the event that the value of the form is modified by user. At this point, the real value of the component is the value just entered by the user, and the bound data has not yet been updated. In this case, if the bound data is modified with the old value, Vue will incorrectly perform the optimization.

Therefore, to ensure that this assumption always holds. v-modle should always be used to make the data consistent with the true value.