Front end | Vue nextTick gets the updated DOM

Posted by sasori on Tue, 25 Jan 2022 05:24:50 +0100

I met a requirement during development two days ago: when opening the dialog box, I automatically focus on the input box. Since the native autofocus attribute does not work, you need to manually obtain the focus using the focus method provided by the component library. So there is the following code:

<el-button @click="openDialog">Click open Dialog</el-button>

<el-dialog :visible.sync="dialogVisible">
  <el-input v-model="input" ref="input"></el-input>
</el-dialog>
methods: {
  openDialog() {
    this.dialogVisible = true;
    const input = this.$refs.input;
    input.focus();
  },
},

The result is an error because the input component is not obtained; This is also verified by log$ refs. The value of input is indeed undefined. However, after testing, if the dialog box is open by default, no error will be reported; Obviously, the component is there. Why can't you get it?

Lifecycle update

After analysis, this phenomenon is caused by the update mechanism of Vue instances. As can be seen from the life cycle diagram (partial) below, after the component is loaded, the virtual DOM (which can be understood as the component node in HTML) will be re rendered when the data changes. In this example, the hidden Dialog component (and its input component) is not rendered in the DOM, but is updated and rendered after observing that the dialogVisible attribute becomes true.

Web page rendering is usually an asynchronous task, so when the visible property is just changed (a function is a synchronous process), DOM rendering has not been carried out, so it is natural to get the input component that does not exist at this time.

For more information on the concepts of asynchrony, JS task queue, macro task and micro task, please refer to the blog JS multithreading: task queue

In order to show this process more intuitively, you can try to get the component and print it in the hook function before and after the update:

beforeUpdate() {
  console.log("beforeUpdate");
  const input = this.$refs.input;
  console.log(input);
},
updated() {
  console.log("updated");
  const input = this.$refs.input;
  console.log(input);
},
methods: {
  openDialog() {
    this.dialogVisible = true;
    console.log("click open");
  },
},

The results are as follows, which can verify the previous analysis and conjecture:

click open
beforeUpdate
undefined
updated
VueComponent {...}

Vue.nextTick

To solve this problem, Vue provides a global api Nexttick(), which is used to provide a callback after the next DOM update. That is to say, after calling api after updating data, you can get the re rendered DOM and perform related operations.

The nextTick method can be widely used in various scenarios that need to operate the relevant DOM after data update, such as v-if, watch, etc.

Add nextTick to the above example:

openDialog() {
  this.dialogVisible = true;
  console.log("click open");
  this.$nextTick(function () {
    console.log("next tick");
    const input = this.$refs.input;
    console.log(input);
    input.focus();
  });
},

You can see that the callback is indeed executed after the DOM is updated, that is, after the updated is executed. The operations of obtaining components and manually obtaining focus can also be performed correctly.

click open
beforeUpdate
undefined
updated
VueComponent {...}
next tick
VueComponent {...}

Promise

If no callback parameter is provided and the browser supports Promise, calling nextTick will return a Promise. In other words, the following expressions are equivalent (if supported by the environment):

Vue.nextTick(function () {...})
Vue.nextTick(() => {...})

Vue.nextTick().then(function () {...})
Vue.nextTick().then(() => {...})

For the introduction and usage of Promise, please refer to the blog JS Promise.

Conclusion & References

The above is my personal understanding and thinking about nextTick api in Vue. I hope I can help you. If there are any questions or omissions, please discuss and correct them in the comments.

I will continue to update my study notes in my personal blog, focusing on front-end technology (Vue framework). If you are interested, please pay attention!

reference material:

Vue documentation - api

Vue document - instance

Topics: Front-end