Practical use of Components and Mixins in Vue JS

In this post we will take a deep look into Components and Mixins in Vue JS, you must be familiar with components as its provider by all major JS frameworks out there. They help you extend basic HTML elements to encapsulate reusable code. At a high level, components are custom elements that Vue’s compiler attaches behaviors and mixins give you a place to keep reusable code which keeps your code base DRY and easily maintainable.

Vue Components

A component is a piece of UI which can be reused and it encapsulates all the behavior and functionality in it. for example, a date input in Chrome is a component provided by the browser, it gives you calendar popup to choose a date, you just need to add an input with type date <input type="date"> and you have all the functionality magically available to pic a date. Similarly, Vue gives you the option to create your own custom component. If you want to build a SPA you probably need one root component something like App <app> component which generally acts like wrapper and houses all the root level state.

Create a Component

Now let’s create a component in Vue JS, we will be building a panel component, here is what we wanted it to look like.

Nothing fancy, a simple component needs a name which will be used as element tag and a template which is be rendered by that tag, in this case, we used <bs-panel></bs-panel> its good idea to prefix your component so they don’t collide with another third party component name.

Passing data into Component ↓

Currently, our panel is not doing anything, it’s just showing placeholder text we added in template, wouldn’t it be nice to customize the title and body of this panel using some attribute, vue component can accept data from outside scope using props, lets define it so we can make the title and body dynamic.

As you can see I have add props on the component, now in template, we can use them like {{ title }} and {{ body }} to access the value passed as HTML element attribute. You can pass any data as literal using <bs-panel title="some literal string"></bs-panel> or if you want to bind it to a variable you can use v-bind:title="titleVar" and shorthand is also available as :title="titleVar" both will pass the content of titleVar. It makes our component reusable, in one panel we are showing users details in another his posts.

Create a Child component

You can nest components inside another component, let’s build a follow component which will work like a toggle to follow a user.

In User List component we get the users from https://reqres.in and then list them into a list, you can see we have added a new Follow component which is added below the name of the user in user-list template. So you can nest any component inside another component. You can click on follow button it will toggle state, an event can be bind using v-on:click="toggle" or you can use @click="toggle" both are same, you also have event modifier like@click.prevent="toggle" which will prevent the default action. Now how we notify the user list component that a user follow state has been changed. Let’s see that next:

Passing data from Child to Parent component ↑

Vue comes with pub sub event system, you can use vm.$emit('myEvent', payload) to fire event which can listen by the parent component. Let’s emit followed event when user clicks follow button on Follow component, which we will listen in Parent User List component.

As you can see above User List component method handleFollowed(payload) get triggered when we vm.$emit('followed', payload) event from Follow child component toggle() method. This way we can communicate from child to parent controller.

Use slot to customize the template

Props are good for passing variables and expression, but if you wanted to pass HTML it’s not going to work, you can customize the template using slot provided by Vue which makes a component very flexible. Let’s use our Panel component and add a slot in it.

Adding slot in component is probably easiest, you just need to edit template and add <slot></slot> tag, if you wanted to add named slot then add the nam also,<slot name="title"></slot> now to use it you just need to pass your content inside components tags like

<bs-panel>
   <!-- default slot -->
   I will be shown in default slot 

  <div slot="title">
     As you guessed I will end up in title slot
  </div>
</bs-panel>

Scoped Slot

Ever been in a situation where you are creating similar Components with slight variation in template rendering? Luckily from Vue version 2.1.0+ you have scoped slot, which gives you access to your component scope data inside its slot template. Let me show you how you can use it in your project.

For example, you have List Component which accesses some data from some endpoint and renderers it in a list. Let’s create List component.

Similar to a normal slot, if you wanted to turn it into scoped slot you just need to tweak component template only, no need to do anything else:

<li v-for="item in result" class="list-group-item">
    <!-- passed item as prop to slot -->
    <slot :item="item">
      {{ item.first_name + ' ' + item.last_name }}
    </slot>          
</li>

Now you can access scope props from q-list component slot template like this:

<q-list 
  title="Photo List"
  url="https://jsonplaceholder.typicode.com/photos?_page=4">
  <!-- custom template -->
  <template scope="props">
        <img 
          :src="props.item.url" alt=""
          class="img-responsive">
        <h4>{{ props.item.title }}</h4>
  </template>
</q-list>

That’s it, as you can see in the demo I have created 4 separate variations using single component with the power of scoped slots in Vue.js.

Using Laravel Blade in Vue template

Vue js supports inline-template, you can use your current blade template as vue template, it gives you flexibility to use your blade directive in conjunction with Vue event binding and rendering option, and it saves you from passing data into the component using props.

Let’s create a setting Component in laravel, open resources/assets/js/components/Setting.vue and just export the default object, no need of template since we will be using an inline template.

<script>
    export default {
        methods: {
            submit() {

            }
        }
    }
</script>

Now register your component in app.js

Vue.component('setting', require('./components/Setting.vue'));

Now to use an inline template you call your component with inline-template attribute:

<setting inline-template>
    @include('partial.setting')
    <input type="email" name="from_email" value="{{ old('from_email') }}">
    <button @click.prevent="submit">Save Settings</button>
    ...
</setting>

As you can see you have full access to your blade directives and all the features Vue offers inside a template.

Lifecycle hooks of Vue Components

Here are the hooks which get fired in the lifecycle of a vue component/instance. All lifecycle hooks automatically have their this context bound to the instance, so that you can access data, computed properties, and methods.

Lifecycle hooks of Vue Components

beforeCreate

Called synchronously after the instance has just been initialized, before data observation and event/watcher setup.

created

Called synchronously after the instance is created. At this stage, the instance has finished processing the options which mean the following have been set up: data observation, computed properties, methods, watch/event callbacks. However, the mounting phase has not been started, and the $el property will not be available yet.

beforeMount

Called right before the mounting begins: the render function is about to be called for the first time.

mounted

Called after the instance has just been mounted where el is replaced by the newly created vm.$el. If the root instance is mounted to an in-document element, vm.$el will also be in-document when mounted is called.

beforeUpdate

Called when the data changes, before the virtual DOM is re-rendered and patched.

You can perform further state changes in this hook and they will not trigger additional re-renders.

updated

Called after a data change causes the virtual DOM to be re-rendered and patched.

The component’s DOM will have been updated when this hook is called, so you can perform DOM-dependent operations here. However, in most cases, you should avoid changing state inside the hook. To react to state changes, it’s usually better to use a computed property or watcher instead.

beforeDestroy

Called right before a Vue instance is destroyed. At this stage, the instance is still fully functional.

destroyed

Called after a Vue instance has been destroyed. When this hook is called, all directives of the Vue instance have been unbound, all event listeners have been removed, and all child Vue instances have also been destroyed.

Check out this fiddle and open the console to see the lifecycle hooks fired

Vue Mixins

Mixins are a flexible way to distribute reusable functionalities for Vue components. A mixin object can contain any component options. When a component uses a mixin, all options in the mixin will be “mixed” into the component’s own options. You can think it as Trait in laravel.

Build State and Close mixins

You might have seen in bootstrap many components can have states like, success, error, warning, info etc. and if you want to add some behaviour like giving option to so Loading, Warning, Error state on a button you can create a mixin in vue, since not only button but other components like Alert, Panel, Table can also have those state.

Let’s build a mixin which we can reuse in components.

We have created stateableMixin and closableMixin mixins, state gives opthe optiono pass type of element you wanted, I have used bootstrap so I can use different state using this, and closable mixin is to add closing and toggle behaviour in any component which needs it, one component can use more than one mixin, like bs-panel and bs-alert component does.

That’s the gist of it, using mixn you can create a consistant api to work with your component throughout the app, and you can always maintain your mixin in one place which will benefit all the components using it.

Thats it in this post, if you like or have any suggestions please let me know in comments also if you want me to cover any other aspect of Vue let me know. I hope you learned something in this post. See you seen in next one.