Components and Single File Components In Vue JS

Check out the previous post What Is A Vue Instance? in this series.

Vue works on the principle of reusable visual components. Each component is a Vue instance which is nested under the root Vue instance. These instances manage and reactively render their virtual DOM to the real DOM according to changes in their state and or  the state of their children.

A Vue app is a composition of components each with their own state, that is mutated according to lifecycle hooks, methods, and event listeners (more on those later). While these components can be declared in pure JavaScript, and passed HTML templates as strings, this is not the preferred way to work. Instead developers use .vue files.

Vue's "single-file components" or .vue files have their own scoped HTML, JavaScript and CSS that compile into Vue instances. In specific, these files have three sections (template, script and style) containing the components HTML, JavaScript and CSS, that define the Vue instance properties and are added to the virtual DOM and rendered as desired. You can see an example of a single-file component by opening App.vue. This file might seem bit strange but we'll take it section by section.

<template>
  <div id="app">
    <img alt="Vue logo" src="./assets/logo.png">
    <HelloWorld msg="Welcome to Your Vue.js App"/>
  </div>
</template>

<script>
import HelloWorld from './components/HelloWorld.vue'

export default {
  name: 'app',
  components: {
    HelloWorld
  }
}
</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>

The first template section is the Vue instance's template HTML. In pure JavaScript this would be a string literal passed as a property of the options object like new Vue({ template: Hello })). It is an HTML-based template syntax that allows you to declaratively bind the rendered DOM to the underlying Vue instance's data.

The script section is where the remainder of instance properties are defined and exported for compilation. However, the App component is not doing much here besides registering a subcomponent called HelloWorld that is bound and rendered in the template section above.

Finally, the style section is used for defining CSS related to a component's visual appearance. It can be on a global or scoped in level which is pretty handy. Let's open the HelloWorld component to get another look into what is going on.

HelloWorld.vue

Below is an excerpt of HelloWorld.vue component that is rendered by App.vue.

<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
    <p>
      For a guide and recipes on how to configure / customize this project,<br>
      check out the
      <a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>.
    // ... rest of template code
    </p>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  props: {
    msg: String
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
// ... scoped css
</style>
HelloWorld.vue

In the template section we can see familiar HTML elements like div, p, etc, in addition to an expression {{ msg }} which is bound to the value in the Vue instance's props or data (depending on declaration). Let's take a look at the script section for more insight.

The script section shows that the msg variable is declared from props which is data passed down by the parent component (e.g. App). This variable is bound to the template, and renders whatever value provided by the parent component. This variable could alternatively be declared from a Vue instance's data function instead. If you remove the props definition, and replace it with data as seen below, the Vue app will re-render and look exactly the same.

<script>
export default {
  name: 'HelloWorld',
  data() {
    return {
      msg: 'Welcome to Your Vue.js App'
    }
  }
}
</script>

So what's the difference between props and data? For starters, data is a component's in-memory and private storage for values, whereas, props is data passed from parent to child components. Both are "reactive" in that if either change, the component will re-render. However, data is mutable storage and props is not intended to be. That is, props are a mechanism of one way data flow and communication from the parent to child components, and as such are not advised to mutate (if they are Vue will send a warning message to the console). Both props and data are linked to the rendered DOM through the Vue instance but have different utilities.