Nwose Lotanna Web Developer and Writer

Accessing the virtual DOM using render functions in Vue JS

4 min read 1306

In this post, we will look at how to use render functions to unleash the power of JavaScript by using templates in Vue.

Before you start

This post is suited for developers of all stages including beginners. Here are a few things you should already have before going through this article.

You will need the following on your pc:

  • Node.js version 10.x and above installed. You can verify if you do by running the command below in your terminal/command prompt:
node -v
  • A code editor: Visual Studio Code is highly recommended
  • Vue’s latest version, installed globally on your machine
  • Vue CLI 3.0 installed on your machine. To do this, uninstall the old CLI version first:
npm uninstall -g vue-cli

then install the new one:

npm install -g @vue/cli
  • Download a Vue starter project here
  • Unzip the downloaded project
  • Navigate into the unzipped file and run the command to keep all the dependencies up-to-date:
npm install

Introduction: How Vue works in browsers

Vue JS has a focus on the view layer of your JavaScript projects and that is why the templates are provided to show your presentation (markup language). The node is the smallest unit of constructs in the DOM, so when template code like this is sent to the DOM, the browser breaks it all down to nodes:

<div> 
 <h1>My first heading is this </h1>
 <p>The paragraph text stays here </p>
</div>

So the heading is a node and the header text is a child node inside the header node, just as the paragraph is a node and the text in it is a child node. To update these nodes, Vue, provides a template to write the presentation code while it assembles the nodes.

So for a paragraph like the one above, you simply write this in the template section:

<p>The paragraph text stays here </p>

Or use a render function to create it, like this:

render: function (createElement) {
  return createElement('p', 'The paragraph text stays here')
}

You can quickly notice the level of abstraction you get with Vue as you compare both methods. The render function, however, closer to the compiler as the template code will still need transcribing to JavaScript.

How Vue manages nodes

To monitor and properly manage these nodes, Vue JS builds a virtual DOM where it does the dirty work of keeping up with nodes and how they change from the point of mounting onInit to when they are un-mounted (at onDestroy) as virtual nodes. A virtual DOM is simply a component tree of all the virtual nodes.

Render function

This is the function in JavaScript used inside a Vue component to perform tasks like creating an element. Here we see the function that is shown above:

render: function (createElement) {
      return createElement('p', 'The paragraph text stays here')
    }

You see that the argument createElement is used to create a new element in the DOM, behind the scenes it returns a virtual node. Virtual nodes are called VNodes in Vue JS.

The render function’s createElement accepts up to three parameters:

  1. The first parameter is called the render element, it is required for createElement to work, it can be a string or even a function. It is usually an HTML tag name, a component option or a function that resolves to a tag name.
  2.  The second parameter is the definition of the component or the HTML tag name in the last parameter. It is usually an object and it is an optional parameter. It is a data object that corresponds to the parameter that will be created in the DOM.
  3. The third parameter is the children parameter, it can either be a string or an array of the data value or child node of the first parameter.

Demo

To illustrate the render function, let us see a sample example, if you read this post from the start you will have downloaded the starter project, unzipped and opened it up in your VS Code application. Open your App.vue file and make sure it looks like this:

<template>
  <div id="app">
    <p>{{greetings}} </p>
  </div>
</template>
<script>
import Test from './components/Test.vue'
export default {
  name: 'app',
  components: {
    Test
  },
  data(){
    return {
      greetings: 'The paragraph text stays here'
    }
  }
}
</script>
<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

This is exactly what we had as our first code sample at the start of this post. To use the render function approach, remember it is a pure JavaScript concept in Vue so open up the main.js file, it should look like this:

import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
new Vue({
  render: h => h(App),
}).$mount('#app')

This is where the default mounting statement is kept by Vue and how the app.vue file is the root component. Add this code block before the new Vue code block, just immediately after the third line:

import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
Vue.component('Hello', {
   render(createElement){
    return createElement('p', 'The rendered paragraph text stays here');
 }
})
new Vue({
  render: h => h(App),
}).$mount('#app')

This creates a new Vue component called Hello and then creates a paragraph element inside it. The paragraph will look exactly as if you opened a new .vue file like the Test component in the project directory. To test it out, go back to the app.vue file and add the Hello component in the template and watch it appear in your browser.

<template>
  <div id="app">
    <p>{{greetings}} </p>
    <Hello />
  </div>
</template>

Here is what it will look like in the browser:

Utilizing the power of JavaScript

You can leverage your knowledge of JavaScript to really control the virtual DOM as you already know that using the render function gives you direct control to the Vue virtual DOM. You can add a data object with values and then use this to refer to it like this:

Vue.component('Hello', {
  render(createElement){
    return createElement('p', this.greetings);
  },
  data(){
    return {
      greetings: 'The paragraph text stays here'
    }
  }
})

This displays the created paragraph with the text specified in the data object.

Using props

You can also make use of your favorite Vue JS constructs like props, for instance. If your app.vue template section has a car property like this:

<template>
  <div id="app">
    <p>{{greetings}} </p>
    <Hello car=" driving a Ferari"/>
  </div>
</template>

You can make reference to it using the props in the main.js file like this:

Vue.component('Hello', {
  render(createElement){
    return createElement('p', this.greetings + this.car);
  },
  data(){
    return {
      greetings: 'The paragraph text stays here'
    }
  },
  props: ['car']
})

Here is what it will look like in the browser:
render createElement

Creating nested components

You can also nest elements with the render function like this:

Vue.component('Hello', {
      render(createElement){
        return createElement('ul', 
          [createElement('li',[createElement('p', 'I am a nested list item')])]);
      },
      data(){
        return {
          greetings: 'The paragraph text stays here'
        }
      },
      props: ['car']
    })

Here is what it will look like in the browser:

nested item list ui

You can see the Vue instance API and the render function documentation here.

Conclusion

This has been a good introduction into accessing the Vue virtual DOM with render functions. It is a very direct way to communicate with the DOM and with knowledge of both Vue and JavaScript itself, you can comfortably have total control over the DOM. Happy hacking!

 

Plug: , a DVR for web apps

LogRocket is a frontend logging tool that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.

In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page apps.

.
Nwose Lotanna Web Developer and Writer

Leave a Reply