Anjolaoluwa Adebayo-Oyetoro Maker. Writes sometimes. playful most times. loves beautiful UIs

Using JSX with Vue

6 min read 1787

The common way to build Vue apps is by using templates. It is not as common to build Vue apps using render functions and JSX. In this tutorial, we will learn what render functions are and how they work. We will also take a look at what JSX is and why you might want to use it in your Vue project.

Prerequisites:

The following is required to follow along with this tutorial:

  • Node.js 10x or higher and Yarn / npm 5.2 or higher installed on your PC
  • Basic knowledge of JavaScript, React, and/or Vue fundamentals
  • Vue CLI installed on your PC, which you can do with the following command using yarn:
yarn global add @vue/cli

Getting started

What are render functions?

A render function is any function that returns a virtual DOM, they are what template code gets compiled to during the build process. The compiled code returns a virtual DOM which Vue processes to generate the actual browser DOM accordingly.

Render functions are closer to compiler alternatives than templates or JSX, they leverage on the document.createElement() Web API method to create HTML documents.

How do render functions work?

A typical render function looks like this:

render (createElement){
 return createElement( 'div', {}, [....]
)}

The createElement method takes in three arguments:

  • A render element, which can be an HTML tag name or a component
  • An object that can contain data objects such as attributes, props, DOM props, styles, classes, and event handlers
  • A child argument that can either be an array of children nodes, a single child node or plain text

The createElement parameter in render functions is often written as h to denote Hyperscript as explained by Evan You — the creator of Vue.

Hyperscript stands for the script that generates HTML structures and helps create markups with JavaScript. The render function above can be rewritten like this:

render (h){
 return h( 'div', {}, [....]
)}
rendering process
A visual of the rendering process

The Virtual DOM

According to Evan You:

The Virtual DOM is a lightweight representation of what the actual DOM should look like at a given point in time

Vue creates a Virtual DOM that keeps track of all the changes made to the real DOM and on every data change Vue returns a new Virtual DOM, it then compares the old virtual DOM to the new one and checks for specific changes and makes adjustments in the real DOM.

The process of comparing and checking changes between the old and the new Virtual DOM is referred to as diffing.

This mini-app helps explore the Vue templates and render functions, you can learn more about render functions in Vue and the Virtual DOM here.

What is JSX?

JSX is an XML-like syntax extension for writing JavaScript. It’s a syntactic abstraction of render functions. It was built by Facebook’s engineering team and originally intended to be used in building React apps in a more concise and elegant way.

JSX, similar to Vue templates, get compiled to render functions under the hood at build time.

Why you might want to use JSX in your Vue project

  • It makes no assumption about how your code should look or be processed. There is no defined way to write JSX
  • JSX helps prevent cross-site scripting attacks because you can never inject code that is not explicitly written in your application, everything is converted to a string before being rendered
  • JSX is dynamic. It gives you the power to do whatever you want to as it gives access to the full programmatic powers of JavaScript
  • There is no registration of imported components, you can make use of them on the go
  • It couples logic and markup together, you don’t have to write markup separately from the JavaScript
  • Several components can be written in a single file as opposed to templates where you have to write every component in separate files
  • JSX gives access to the spread operator, it makes things, like passing an object as props, easier

Common Vue template features and their JSX implementation

Conditionals (v-if)

Template implementation

<template>
   <div v-if="user.age > 18">
      Welcome, {{user.name}}
    </div>
</template>

The block of code above displays a user’s name if the user’s age is greater than 18.

JSX implementation

export default {
....
  methods: {
      checkStatement(){
        if (this.user.age > 18) {
           return <div> Welcome, { this.user.name }</div>;
        }
      }
    },
    render(){
      return(
        {this.checkStatement()}
      )
    }
}

In JSX, the condition to check for a user’s age is wrapped in a function housed inside the Vue method instance and then the function is invoked in the render method.

Loops (v-for)

Template implementation

 <template>
  <div v-for="item in items" :key="item.id">
      {{ item }}
  </div
</template>

The v-for directive executes a block of code a number of times. In the code above we use the v-for directive to render a list of items in an array.

JSX implementation

render(){
  return(
    {this.items.map(item => {
        return (
           <div> {item} </div>
          )
      }
  )}

In JSX, the items in an array can be mapped over, using the ES2015 .map() method.

Events(v-on)

Template implementation

<template>
    <div>
      <button v-on:click="handleButtonClick()"> click me</button>
    </div>
</template>
<script>
export default {
  methods: {
      handleButtonClick(e){
          e.preventDefault();
          alert('button clicked')
        }   
    }
</script>

The v-on directive listens to DOM events and triggers a function that performs a defined operation. In the code shown above, a click of the button triggers the handleButtonClick() function which displays an alert() dialog box.

JSX implementation

export default {
  methods: {
      handleButtonClick(e){
          e.preventDefault();
          alert('button clicked')
        }   
    },
  render(){
    return(
    <div>
       <button onClick={this.handleButtonClick}> click me</button>
    </div>
    )
  }
}

Interpolation (v-html)

Template implementation

<template>
  <div>
     <div v-html="rawHtml"> </div>
  </div>
</template>
<script>
export default {
    data () {
      return {
        rawHtml: "<h1> This is some HTML </h1>",
      }
    }
}
</script>

v-html is used to set elements innerHTML, the code above sets the innerHTML of the div to the content of rawHtml.

JSX implementation

export default {
    data () {
      return {
        rawHtml: "<h1> This is some HTML </h1>",
      }
    },
    render(){
        return(
          <div>
            <div domPropsInnerHTML={this.rawHtml}> </div>
          </div>
        )
      }
}

domPropsInnerHTML attribute performs the same task as v-html , it sets the content of the div to rawHtml.

Importing components

Template implementation

<template>
  <div>
    <NewComponent/>
  </div>
</template>
<script>
import NewComponent from "NewComponent.vue";
export default {
  data () {
    return {
      components:{
        NewComponent,
      },
</script>

JSX implementation

When using JSX there’s no need to register a component after importing it, you can just use it directly.

import NewComponent from 'NewComponent.vue'
....
  render(){
    return(
     <div> <NewComponent/></div>
    )
  }

How to set up a Vue project with JSX

For this section, we will be building a trivial app that displays a little bit of information about selected countries.

Create a new project

vue create vue-jsx

Install the dependencies needed to make use of JSX in your project using yarn:

yarn add @vue/babel-preset-jsx @vue/babel-helper-vue-jsx-merge-props

Configure your babel file to use the presets for JSX by including the following in your .babelrc or babel.config.js file, located in your project root directory:

{
  "presets": ["@vue/babel-preset-jsx"],
}

The @vue/babel-preset-jsx preset enables you to use the JSX presets made available by the Vue team.

Vue automatically injects h which is short for createElement in every method, so you don’t have to always declare h as a parameter in your render() function.

Testing out our Vue-JSX app

To test it out, replace the content of your HelloWorld.vue file in src/components folder with the following:

<script>
export default {
  data () {
    return {
      countries: [
        {
          name: 'Nigeria',
          description: "Nigeria is a large country that has a varied topography. It is about twice the size of the U.S. state of California and is located between Benin and Cameroon. It is the most populated country in africa"
        },
        {
          name: 'USA',
          description: "The United States of America (USA), commonly known as the United States (U.S. or US) or America, is a country comprising 50 states, a federal district, five major self-governing territories, and various possessions."
        },
        {
          name: 'China',
          description: "The People's Republic of China, simply known as China (Chinese:中国, pinyin: zhōng guó)is located in East Asia. It is the world's most populous country, with a population of around 1.404 billion. It is a unified multi-ethnic country with the Han nationality as the main nation."
        },
        {
          name: 'Argentina',
          description: "Argentina is a vast country located in the southern part of South America. The eighth largest country in the world, it is the second largest country in South America after Brazil, and it's about one-third the size of the United States. Argentina is bordered by the Andes Mountains and Chile to the west."
        },
         {
          name: 'Cameroon',
          description: "Cameroon is sometimes described as 'Africa in miniature' because it exhibits all the major climates and vegetation of the continent: mountains, desert, rain forest, savanna grassland, and ocean coastland. Cameroon can be divided into five geographic zones."
         },
         {
          name: 'Somalia',
          description: "With a land area of 637,657 square kilometers, Somalia's terrain consists mainly of plateaus, plains and highlands. Its coastline is more than 3,333 kilometers in length, the longest of mainland Africa and the Middle East. It has been described as being roughly shaped like a tilted number seven."
        }
      ]
    }
  },
  props: {
    msg: String
  },
  methods: {
    //where you write methods or functions used in your component
  },
  render () {
    return (
      <div>
        <div class="content">
          <h1>Hello, { this.msg } </h1>
          <main class="country-wrapper">
            {
              this.countries.map(country => {
                return (
                  <div class="country-container">
                    <h3 class="country-name ">{country.name}</h3>
                    <article class="country-description">{country.description}</article>
                  </div>
                )
              })
            }
          </main>
        </div>
      </div>
    )
  }
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
.content{
  width: 100%;
  .country-wrapper{
    width: 100%;
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    .country-container{
      display: flex;
      flex-direction: column;
      text-align:start;
      margin: 1em;
      padding: .5em;
      width: 28%;
      height: 12em;
      border: .08em solid #c4c4c4;
      .country-name{
        margin: 0;
        margin-bottom: 1em;
      }
    }
  }
}
</style>

You should get a result similar to this:

vue.js test app

Conclusion

We’ve seen how render functions work and how to set up a Vue project to use JSX, check out the repository to this article on GitHub. To learn about more awesome things you can do with Vue.js, check out the documentation.

Plug: , a DVR for web apps

LogRocket is a frontend application monitoring solution 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.

.
Anjolaoluwa Adebayo-Oyetoro Maker. Writes sometimes. playful most times. loves beautiful UIs

Leave a Reply