Tutorial

Introduction to Vue.js Render Functions

Published on February 16, 2017
author

Joshua Bemenderfer

Introduction to Vue.js Render Functions

Vue.js templates are incredibly powerful, and can accomplish almost everything you’d ever need in an app. However, there are a few use-cases, often those involving dynamic component creation based on input or slot values that are better served by render functions.

Those coming from a React world are probably very familiar with render functions. React components are built with them, usually through JSX. And while Vue render functions can also be written with JSX, we’re going to stick with raw JS so you can more easily understand the underpinnings of Vue’s component system.

It’s worth noting that Vue.js’ templates actually compile down to render functions at build time. Templates just provide a convenient and familiar syntax sugar on top of render functions. While more powerful, render functions often suffer in the readability department.

Creating a Component

Components with render functions do not have a template tag or property. Instead they define a function called render that receives a createElement(renderElement: String | Component, definition: Object, children: String | Array) argument (commonly aliased as h, for some reason, blame JSX) and returns an element created with that function. Everything else stays the same.

ExampleComponent.vue
export default {
  data() {
    return {
      isRed: true
    }
  },

  /*
   * Same as
   * <template>
   *   <div :class="{'is-red': isRed}">
   *     <p>Example Text</p>
   *   </div>
   * </template>
   */
  render(h) {
    return h('div', {
      'class': {
        'is-red': this.isRed
      }
    }, [
      h('p', 'Example Text')
    ])
  }
}

Replacing Shorthand Directives

Vue templates come with a variety of convenient features in order to add basic logic and binding features to templates. Render functions do not have access to these. Instead, they must be implemented in plain Javascript, which, for most directives, is fairly simple.

v-if

This one is easy. Instead of using v-if, just use a normal Javascript if (expr) statement around your createElement calls.

v-for

v-for can be implemented with any of the many Javascript iteration methods, for, for-of, Array.map, Array.filter, etc.. You can combine these in very interesting ways to implement filtering or state slicing without the need for computed properties.

For example, you could replace

<template>
  <ul>
    <li v-for="pea of pod">
      {{pea.name}}
    </li>
  </ul>
</template>

with

render(h) {
  return h('ul', this.pod.map(pea => h('li', pea.name)));
}

v-model

A good thing to keep in mind is that v-model is simply shorthand for a binding property to value and setting the data property whenever the input event is fired. Unfortunately, there’s no such shorthand for render functions. You have to implement it yourself, as shown below.

render(h) {
  return h('input', {
    domProps: {
      value: this.myBoundProperty
    },
    on: {
      input: e => {
        this.myBoundProperty = e.target.value
      }
    }
  })
}

Which is equivalent to:

<template>
  <input :value="myBoundProperty" @input="myBoundProperty = $event.target.value"/>
</template>

or

<template>
  <input v-model="myBoundProperty"/>
</template>

v-bind

Attribute and property bindings are placed in the element definition, as arttrs, props, and domProps (stuff like value and innerHTML).

render(h) {
  return h('div', {
    attrs: {
      // <div :id="myCustomId">
      id: this.myCustomId
    },

    props: {
      // <div :someProp="someonePutSomethingHere">
      someProp: this.someonePutSomethingHere
    },

    domProps: {
       // <div :value="somethingElse">
      value: this.somethingElse
    }
  });
}

As a side note, class and style bindings are handled directly at the root of the definition, not as attrs, props, or domProps.

render(h) {
  return h('div', {
    // "class" is a reserved keyword in JS, so you have to quote it.
    'class': {
      myClass: true,
      theirClass: false
    },

    style: {
      backgroundColor: 'green'
    }
  });
}

v-on

Event handlers are also added to the element definition directly, in the on (or nativeOn, which has the same effect as v-on.native for components.)

render(h) {
  return h('div', {
    on: {
      click(e) {
        console.log('I got clickeded!')
      }
    }
  });
}

The modifiers can be implemented inside the handler:

  • .stop -> e.stopPropagation()
  • .prevent -> e.preventDefault()
  • .self -> if (e.target !== e.currentTarget) return

Keyboard modifiers

  • .[TARGET_KEY_CODE] -> if (event.keyCode !== TARGET_KEY_CODE) return
  • .[MODIFIER] -> if (!event.MODIFIERKey) return

Special properties

Slots can be accessed through this.$slots as an array of createElement() nodes.

Scoped slots are stored in this.$scopedSlots[scope](props: object) as functions that return an array of createElement() nodes.

Enjoy the new, unlimited power granted to you by render functions! Just be careful to use wisely.

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about our products

About the authors
Default avatar
Joshua Bemenderfer

author

While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.

Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
Leave a comment


This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

Try DigitalOcean for free

Click below to sign up and get $200 of credit to try our products over 60 days!

Sign up

Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

Become a contributor for community

Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

DigitalOcean Documentation

Full documentation for every DigitalOcean product.

Resources for startups and SMBs

The Wave has everything you need to know about building a business, from raising funding to marketing your product.

Get our newsletter

Stay up to date by signing up for DigitalOcean’s Infrastructure as a Newsletter.

New accounts only. By submitting your email you agree to our Privacy Policy

The developer cloud

Scale up as you grow — whether you're running one virtual machine or ten thousand.

Get started for free

Sign up and get $200 in credit for your first 60 days with DigitalOcean.*

*This promotional offer applies to new accounts only.