vue icon indicating copy to clipboard operation
vue copied to clipboard

The flush property of watch does not work when it is post

Open someBrown opened this issue 2 years ago • 0 comments

Version

2.7.14

Reproduction link

codesandbox.io

Steps to reproduce

https://codesandbox.io/s/quizzical-grass-85c9zw?file=/src/components/HelloWorld.vue

What is expected?

if watch has set flush to 'post', it's callback should be called after dom rerender,so that the callback function can get the latest dom

What is actually happening?

The parent component passes a test property to the child component,and the parent component will change this test property when the button is clicked

<template>
  <div id="app">
    <button @click="click">click me!</button>
    <HelloWorld msg="Hello Vue in CodeSandbox!" :test="test" />
  </div>
</template>

<script >
import HelloWorld from "./components/HelloWorld";
import { ref } from "vue";
export default {
  components: { HelloWorld },
  setup() {
    const test = ref(false);
    const click = () => {
      console.log("click");
      test.value = true;
    };

    return {
      click,
      test,
    };
  },
};
</script>

The child component will get the latest dom info in watch after the test property has changed,but it cannot get the latest dom. The {flush: "post"} config not work

<template>
  <div class="hello" :class="{ test }">
    <h1>{{ msg }}</h1>
  </div>
</template>

<script>
import { getCurrentInstance, watch, nextTick } from "vue";
export default {
  name: "HelloWorld",
  props: {
    msg: String,
    test: Boolean,
  },
  setup() {
    const vm = getCurrentInstance().proxy;
    console.log(vm.$props.test);
    watch(
      () => vm.$props.test,
      () => {
        // should print element but print null
        console.log(document.querySelector(".test"));
        nextTick(() => {
          console.log(document.querySelector(".test"));
        });
      },
      {
        flush: "post",
      }
    );
  },
};
</script>

Because when already flushing,no sorting of new incoming watchers based on the post attribute

// if already flushing, splice the watcher based on its id
    // if already past its id, it will be run next immediately.
    let i = queue.length - 1
    while (i > index && queue[i].id > watcher.id) {
      i--
    }
    queue.splice(i + 1, 0, watcher)

someBrown avatar Dec 09 '22 03:12 someBrown