Vue is an adaptable and gradually-adopted JavaScript UI framework. With its distinctive architecture and reactivity system, Vue updates the DOM whenever the JavaScript state changes. However, in certain scenarios, this approach isn’t sufficient, and we need to re-render individual components.
In this article, we’ll review some best practices to efficiently re-render Vue components so we can avoid reloading the entire page. The following four basic practices apply to both Vue 2 and Vue 3. Let’s get started!
Jump ahead:
Hot reload
Hot reload involves more than just reloading a page whenever we update a file. When we modify a component in a *.vue
file with hot reload enabled, Vue will swap all instances of that component without refreshing the page. Therefore, it preserves the present state of our app as well as the swapped components, thereby improving the developer experience whenever you significantly modify the templates or styling of components.
Using hot reload
Whenever you scaffold a project with the Vue CLI, hot reload will be enabled out-of-the-box. Also, when you set up a new project manually, hot reload is enabled automatically when you serve your project with webpack-dev-server --hot
.
For advanced use cases, I recommend checking out vue-hot-reload-api, which is used internally by Vue Loader.
Disabling hot reload
Hot reload is always enabled automatically, except under the following circumstances:
- webpack
target
isnode
(SSR) - webpack minifies the code
process.env.NODE_ENV === 'production'
To specifically disable hot reload, use the hotReload: false
option:
module: { rules: [ { test: /\.vue$/, loader: 'vue-loader', options: { hotReload: false // disables Hot Reload } } ] }
State preservation rules
When re-rendering components, the hot reloading process follows a set of state preservation rules.
When editing the <template>
of a component, instances of the edited component will re-render in place, maintaining all existing private states. This is made possible by combining templates to create new render functions with no side effects.
When a component’s <script>
section is changed, instances of the modified component will be destroyed and re-created in place. This is due to the possibility of side effects from lifecycle hooks in <script>
, necessitating a reload rather than a re-render to maintain consistency.
Therefore, one should exercise caution when using timers or other global side effects inside component lifecycle hooks. Sometimes, if a component has global side effects, we must reload the entire page.
Keep in mind that the application state is unaffected by <style>
hot reload because it runs independently via vue-style-loader
.
The Vue v-if
hack
The v-if
directive, which is included with the Vue library, only renders a component when a given condition is true
. If it’s false
, the component won’t appear in the DOM. Therefore, the creative use of the v-if
directive might be a better solution.
In this template, let’s set up a v-if
directive:
<template> <MyComponent v-if="renderComponent" /> </template>
In the script
section, we’ll add a method called forceRender
, which uses nextTick
, a utility for waiting for the next DOM update flush:
import { nextTick, ref } from 'vue'; const renderComponent = ref(true); const forceRender = async () => { // Here, we'll remove MyComponent renderComponent.value = false; // Then, wait for the change to get flushed to the DOM await nextTick(); // Add MyComponent back in renderComponent.value = true; };
In a scenario where we use the Options API instead of The Composition API, our script
will look more like the following code:
export default { data() { return { renderComponent: true, }; }, methods: { async forceRender() { // Remove MyComponent from the DOM this.renderComponent = false; // Then, wait for the change to get flushed to the DOM await this.$nextTick(); // Add MyComponent back in this.renderComponent = true; } } };
In the code snippet above, renderComponent
is initially set to true
, rendering MyComponent
. Whenever we call forceRender
, renderComponent
is set to false
. Doing so stops rendering MyComponent
because the v-if
directive now evaluates to false
.
Immediately after MyComponent
stops rendering, we wait for a tick and then set renderComponent
back to true
. This also sets the v-if
directive to true
, which renders a refreshed instance of MyComponent
Two elements are crucial to deciphering how nextTick()
operates. First, we must wait until the next tick, unless our updates to renderComponent
will cancel themselves out, and we won’t notice any changes.
In Vue, you can use nextTick()
immediately after a state change to wait for the DOM updates to complete. We can either pass a callback as an argument or await the returned promise.
Vue will destroy the previous component because it creates an entirely new component when we render it for the second time. As a result, our new MyComponent
will go through all of its typical lifecycles, created
, mounted
, and so on.
Vue’s built-in forceUpdate
method
As recommended by the official Vue documentation, the built-in forceUpdate
method is one of the best ways to manually update a component.
Typically, Vue will update the view in response to changes in dependencies. Even though none of the dependencies have changed, we can still force that update to happen by calling the forceUpdate
method, which forces the component instance to re-render.
However, this defeats the purpose of the entire reactivity system; therefore, it is not suggested as a fix in these situations. We mistakenly believe that Vue will respond to changes to a particular property or variable, but that isn’t always how the reactivity system works.
The code below demonstrates how to call the forceUpdate
method using the Vue Options API:
export default { methods: { ForcesUpdateComponent() { // our code this.$forceUpdate(); // Notice we have to use a $ here // our code } } }
This method only exists on the component instance, so we need to get a bit creative to call it using Vue 3’s Composition API:
import { getCurrentInstance } from 'vue'; const methodThatForcesUpdate = () => { // our code const instance = getCurrentInstance(); instance.proxy.forceUpdate(); // our code };
The only case where we may want to use the forceUpdate
method is when we have explicitly created a non-reactive component state using advanced reactivity APIs. However, given Vue’s fully automatic reactivity system, this is optional.
The key-changing technique
Using the key-changing technique, we provide a key
attribute to inform Vue that a particular component is connected to a particular piece of data. If the key
remains the same, the component won’t change. But, if the key
changes, Vue understands that it needs to delete the previous component and generate a new one.
Why does Vue require a key
?
Let’s delve further into what a key
attribute does specifically and why we need it. Let’s assume we’re rendering a list of components that includes one or more of the following:
- A local state
- An initialization process, either with Vue 3’s
setup
function or in thecreated
andmounted
hooks when using the Options API - Non-reactive DOM manipulation achieved through jQuery or Vanilla APIs
When sorting or updating that list, we don’t want to re-render everything on the list; we only want to re-render the parts of the list that we updated. To achieve this, we’ll provide a key
property to help Vue keep track of what has changed and what hasn’t. Since the index of an array is unrelated to specific items on our list, using it in this situation wouldn’t do anything.
The key-changing technique is considered the best way to force Vue to re-render a component. Below is a fundamental way to illustrate it:
<template> <MyComponent :key="componentKey" /> </template> <script> import { ref } from 'vue'; const componentKey = ref(0); const forceRender = () => { componentKey.value += 1; }; </script>
In the code snippet above, we’ll add a key
attribute to MyComponent
, and then change that key
whenever we need MyComponent
to be re-rendered.
Using the Options API instead of Vue 3 or the Composition API, it’ll look like the following:
export default { data() { return { componentKey: 0, }; }, methods: { forceRender() { this.componentKey += 1; } } }
Whenever forceRender
is called, the value of componentKey
will change. When this occurs, Vue will be aware that it must destroy the component and initialize a new one. We’ll also end up with a child component that will reset its state and re-initialize itself.
Conclusion
Ideally, we should be able to utilize Vue’s robust reactivity system and avoid using such crude workarounds, but there are instances where we must force a component to re-render to complete the task at hand. In this article, we covered four different ways to force a Vue component to re-render, including hot reload, the v-if
hack, the forceUpdate
method, and finally, the key-changing technique.
The right one will ultimately depend on the unique situation you find yourself in, however, the key-changing technique is usually a safe bet. I hope you enjoyed this article! Be sure to leave a comment if you have any questions. Happy coding!
The post Best practices for forcing a Vue component to re-render appeared first on LogRocket Blog.
from LogRocket Blog https://ift.tt/GEIUnP4
Gain $200 in a week
via Read more