Subscribe on changes!

No re-rendering occurring upon updating ref value

avatar
Jun 20th 2023

Vue version

3.2.45

Link to minimal reproduction

https://codesandbox.io/s/epic-hellman-hrlnl7?file=/src/App.vue

Steps to reproduce

Text Input Example

  1. Open Link to minimal reproduction
  2. Type something in input field (more than 5 characters)
  3. ref.value has value "limit"
  4. input.value has another value

Checkbox Example

  1. Open Link to minimal reproduction
  2. Check the checkbox
  3. Click cancel in confirm modal
  4. ref.value has value "false"
  5. input.checked has value true

What is expected?

Input value updates after ref.value changed

What is actually happening?

Desynchronization between the reactive value and the value of the DOM element

System Info

No response

Any additional comments?

I've encountered a situation where updating the ref value doesn't cause the expected reaction. As far as I understand, each reference to .value initiates a subscription to the value change, and once this value has changed, a re-render should occur. The rendering engine creates an updated version of the virtual DOM, compares it with the current virtual DOM, and if any changes are detected, redraws the corresponding elements in the real DOM. In this case, it seems that the engine should respond to the change of the ref value and re-render the element, updating its value. However, for some reason, this does not happen.

I would greatly appreciate it if you could help me understand why this behavior occurs. I'm not necessarily looking for a solution right now, but I want to comprehend what exactly is happening during the re-rendering phases and why it's not working as I expect.

Also I found the same issue in vue 2 https://github.com/vuejs/vue/issues/11621 but there is no valid answer

Thank you in advance for your time and assistance.

avatar
Jun 20th 2023

I saw some workarounds like this in mature UI libraries

avatar
Jun 22nd 2023

You are not actually updating the ref value. it's false before clicking the checkbox, and after you update it, it's still false when you cancel the prompt. So Vue does not have a reason to re-render. Nothing changed.

But the HTML Element did change already. So that's the reason why your data is now out of sync.

A possible more Vue-y solutionm than what @xrsdww linked to, would be to use something like this:

<input type="checkbox" v-model="checked" @click="guardChecked" />
const checked = ref(false);
const guardChecked = (event) => {
   const isConfirmed = window.confirm("Are you sure?");
    // preventing the click event's default will prevent the checkbox from togglinh its checked state.
    // that will in turn prevent the input and change events from firing,
    // and so the checkbox as well as the v-model value will stay as they are
     if (!isConfirmed) { event.preventDefault() }
};
avatar
Jun 22nd 2023

You are absolutely right. It looks like I dived too deep, but I didn't notice the obvious reason