Add Vue to your acknowledged stack
Tags: vue, react, frontend, javascript
Published: 2018-08-13 13:09:23

---
title: Add Vue to your acknowledged stack
published: true
description: If you are a front end developer and still didn't look at Vue because "Why I need to, when I am happy with React?", then this article is for you. I will try to give you a quick glance at Vue to increase your curiosity. P.S. there is even getDerivedStateFromProps mention!
tags: vue, react, frontend, javascript
cover_image: https://blog.pusher.com/wp-content/uploads/2018/03/building-external-modules-vuejs-header.png
---

### TL;DR

Vue.js can't be called "same good as React" (or even "better"). React, as a code library, its tricks and architectural decisions (like Fiber or Time-slicing, Suspense and Hooks), push JS development way further than we could ever expect, it also taught me to think functional which helps a lot in writing any applications using any technology. But Vue.js approach, as for me, slightly different. It gives you focus on the product you develop rather than code you write. At the same time, I believe that 99% of projects could be developed with Vue instead of React with no differences in functionality and performance. But Vue makes you happy. It has so huge amount of small helpers, tips, and tricks, that when you try to build stuff with React again you think "Why the hell I should I write all this boilerplate over and over, and over, and over again?". Vuex is one of the core libraries (see what it means) that give you single-source-of-troth store with jeez convenient way of usage, decreasing you code-base, which leads to fewer places for bugs. vue-router is another core library, that gives you all you need with minimal setup, but very flexible if you need something complicated. I won't even mention powerful UI and UX improvements provided by `transition` and `transition-groups` in Vue out of the box, that makes any app better. Do I think that Vue is better than React? Nope, React is still more popular and blows my mind once a year (again Fiber, Suspense). But would I use React for any next project? Nope, nope, nope. With Vue.js developer experience is way better, I would rather go with it.

## Let's start

Okay, I know that React developers are very busy, no time for more intro. Let's create a new Vue project:

```bash
npx @vue/cli create simple-sample
```

We can now select features we want in our setup:
![Vue features setup](https://thepracticaldev.s3.amazonaws.com/i/9ihbumegzmoofdhzeg5e.png)

I selected TypeScript because we like safe types, I don't need any preprocessors, because PostCSS included by default, and [vuex](https://vuex.vuejs.org/) with [vue-router](https://router.vuejs.org/) because those are important parts of Vue ecosystem. We want to use class syntax (yeah, it's not default) because classes are familiar and look good. So we have our setup like:
![vue project setup](https://thepracticaldev.s3.amazonaws.com/i/k7flabpu8v48bmekni37.png)

Quick dependencies installation and now we can see the project structure:

![Initial project structure](https://thepracticaldev.s3.amazonaws.com/i/psv8bvjlztlbi7km32zk.png)

`shims-` just a setup for TS, to use this awesome typed JavaScript in `.vue` Single File Components. You probably heard about SFC already: we don't have to, but we can write our components in one file and be happy with it!
Why? Well, because your component usually is a skeleton (template), behavior (script) and look (style). So let's create our `vue` file in **components** folder* and write our component. I called it `DevToHeader.vue`.
###### (quicktip: [Vetur](https://marketplace.visualstudio.com/items?itemName=octref.vetur) is a Vue syntax helper for VS Code)

## Quick intro to templates

* Templates are valid html
* if you need to bind some data to template, you use `v-bind` (nobody does that**, use `:`), e.g. `:prop="{ react: 'cool' }"` (same as React, `:prop="true"` is equal to just `prop`)
* if you need to listen to some event, you use `v-on` or shortly `@`. e.g. `@click="functionName"` or feel the power of `@customEvent="handlerOfThisEventName" ` or `@click="$event => handlerFuncName($event, 'my custom data')"` or `@mousedown="mouseDownDataInYourComponent = true"`
* You need to remember only a few directives:
  * `v-for` directive is for loops, iterates through your collection like: `v-for="(value, key) in youObjectOrArray"`, so now you can use your `value` or `key` easily (I hear "meh, why `value` first?", well, you usually do `value in yourArray`)
  * `v-if`, `v-else-if` and `v-else` for conditional rendering, your nice replacement of ternary operators in JSX. Use like `v-if="userLoggedIn"` (or simple `v-show` to `display: none;` of (!)mounted components, you will quickly find out how awesome this helper, no css or inline styles needed now!)
  * `v-model` - your hero that saves you from writing methods that `setState` for each dynamic input. You now can have `<input v-model="searchText" />` that is the same as `<input :value="searchText" @input="updateSearchTextValue)" />` (can you guess what [this example from docs](https://vuejs.org/v2/guide/forms.html#number) does: `<input v-model.number="age" type="number">`?
  * you can see or create a custom one, they usually start with `v-*` and adds some cool features.
* To render some data you use mustaches: `<h2>{{ variableName }}</h2>`, no need those for just text: `<h2>search</h2>`.

That's basically it! Having this knowledge, let's define our template:

```html
<template>
  <header class="main-header">
    <img src="../assets/logo.png" alt="logo" />
    <input placeholder="search" v-model="searchText" />
    <button @click="openModal">Write a post</button>
    <img v-if="user" :src="user.photo" alt="User avatar" />
    <button v-else>Login</button>
  </header>
</template>
```

No questions here, right? Maybe only where is this dynamic data comes from, like `user` or functions like `goToNewPostPage`?

## Let's define data and logic

Now we can go to a script tag. We selected class-based sytax for easier transition from React and we have TypeScript support just for fun. Let's start:

```html
<script lang="ts">
</script>
```

Now let's go to the body:

```ts
// think about this as import React from "react"
import { Component, Vue } from "vue-property-decorator";

// with this decorator we're saying to compile regular Vue component from our class
@Component
export default class DevToHeader extends Vue {
    user:User = null;
    searchText:string = ""; // two-way binding in v-model works with this guy

    openModal(event: Event) {
      this.$emit('openCreatePostModal', event);
    }
}

type User = IUser | null;

interface IUser {
  photo: string;
  name: string;
}
```

In this way, we defined data in our component and method that `$emits` data. Remember that `@customEvent="handlerForIt"`? Well, now a parent of our `header` can listen to the event `@openCreatePostModal="handlerForIt"` and the handler will receive `event` as an argument. And we can pass any data we want to our parent.
###### some vue-specific methods or data always start from `$` sign.
 
Q: Where is our `componentDidMount`?
Well, just define a `mounted` method:
```ts
  // ...
  async mounted() {
    this.user = await fetchUserData()
  }
  // ...
```
User updates -> component updates -> view updates. Easy.

Q: What about `static getDerivedStateFromProps(props, state)`?
Okay, let's pretend that we get `username` from parent and we want to change the path to the avatar depending on `username`. For this, we to change a bit:

```ts
import { Component, Vue, Prop } from "vue-property-decorator";

@Component
export default class DevToHeader extends Vue {
    @Prop({
      type: String, // your `prop-types` checks out of the box
      default: null // we don't really need that
    })
    username:string | null = null; // now for TypeScript
    // our photo src path that we will use as img :src
    photoSrcPath: string | null = null;
  // ...
}
```

All `props` are available as instance properties, the same way as our self-defined data. Let's add adding path now:
```ts
// import Watch decorator
import { Component, Vue, Prop, Watch } from "vue-property-decorator";

// ... or component class
    // watch for 'username' property
    @Watch('username', {
      immediate: true // call this function also on component mount
    })
    changePhotoPath(username:string | null) { // takes (newValue, oldValue)
      this.photoSrcPath = username ? `/user/${username}/data/avatar.png` : null;
    }
// ...
```
So we change our state based on property change, is it the most common case for `getDerivedStateFromProps`? And yes, you can watch for your "state" data propertes as well. Watchers are very powerful 💪.

But how can we handle it in a Vue way? [Computed properties](https://vuejs.org/v2/guide/computed.html)! Since we don't need to change any other data in our component, don't have complex logic and we don't need to make any async requests, it makes sense to have a simple property that will change based on `username`. And computed properties are the way to go, they are performant, they have cache and easy to write and use:

```ts
  // remove photoSrcPath data property
  // define computed property:
  get photoSrcPath():string {
    return `/user/${this.username}/data/avatar.png`
  }
```
Now our `img` tag:
```html
  <img v-if="username" :src="photoSrcPath" alt="User avatar" />
```
Of course you can have any kind of stuff in computed, like I had once a bunch of filters for the same input collection:

```ts
// ...
    get filteredByA() {
      return this.collection.filter(filterByA).map(setFlags);
    }

    get filteredByB() {
      return this.collection.filter(filterByB)
    }

    get filteredByC() {
      return this.collection.filter(filterByC).map(setFlags);
    }
// ...
```
No need to store it in state, implement `shouldComponentUpdate` or stuff. And again, they're very performant.

## Add our component

Let's go to the `views/Home.vue` and add our component there:

```ts
import { Component, Vue } from "vue-property-decorator";
import HelloWorld from "@/components/HelloWorld.vue"; // @ is an alias to /src
import DevToHeader from "@/components/DevToHeader.vue";

@Component({
  components: {
    HelloWorld,
    DevToHeader // becomes 'DevToHeader': DevToHeader
  }
})
export default class Home extends Vue {}
```
Now we pass into decorator some options, specifically `components`. In this way, we're saying to Vue compiler which components we're going to use in our template. Vue automatically changes PascalCase to kebab-case to use in templates (or you can name it yourself, like `'hello-w': HelloWorld`). So inside our `Home.vue` template we can use our component:

```html
  <div class="home">
    <dev-to-header
      username="Alex"
      @openCreatePostModal="$router.push('/newPost')"
    />
    <img alt="Vue logo" src="../assets/logo.png">
    <hello-w msg="Welcome to Your Vue.js + TypeScript App"/>
  </div>
```

We pass "Alex" as a `username` prop and attach a listener to our component. Our header didn't know, but there is no modal, we should just go to another page (yeah, we should rename this event now), so I wrote an inline function here. Remember inliners🔝? They're not very good from DX perspective, but for some simple stuff, to avoid boilerplate, why not? We're people after all...

So this inliner actually calls `this.$router.push('/newPost')`, so what's `$router`?

## **vue-router**

Did you have an experience of your router setup being rewritten a couple of times because of React-Router upgrades? Look at this setup that almost didn't change with time:

{% gist https://gist.github.com/LexSwed/a9b442ba0b38acb671dddaf97cd45868 %}

Already see bundle split on page level thanks to [dynamic import](https://webpack.js.org/guides/code-splitting/#dynamic-imports)?

`Vue.use(Router)` adds a couple of global components for you, that you can use in templates as `<router-view/>` and `<router-link to="/about">About</router-link>`. And superproperties to your Vue instances: `$route` which contains your current route info, like params, query, metadata and `$router` which gives you methods to manipulate router programmatically. Good stuff, good stuff.

## **vuex**

Thanks to Vue.js reactivity system, you don't need `thunks`, `sagas` and `connect`. You just define store, as in the example project, and use it as one more superproperty `this.$store` in your components. Async actions, mutations, modules, middleware - everything is just there. Need one more really awesome abstraction that can reduce your codebase - [vuex-pathify](https://davestewart.github.io/vuex-pathify/#/?id=home) looks pretty.

## You are a weirdo and love JSX

[JSX is supported](https://vuejs.org/v2/guide/render-function.html#JSX), it's a babel abstraction and Vue uses the same `render` method approach as React.

## React.createContext?

Yup, also [there](https://vuejs.org/v2/api/#provide-inject). You define `provide` property in parent component and `inject: ['nameOfPropertyToInject']` in your any depth children component.

## Just try it

There is no point to resist of trying new tools. I often don't understand people who don't like Vue even without really trying it. At the end of the day, this is the tool to improve your productivity, your users happiness. If it doesn't work for you, then leave it, but don't give up early. I had an issue with changing mind back from *everything should be immutable*, calling `this.smth = ...` made me feel like I'm doing something wrong or cheating. No, it's just because we used to write React code (just JS, yes 🙃). Can't not to mention that I also started to improve UX of any app by adding transitions, because they're very easy to set up and use in Vue.

Thanks for reading, see you on Twitter or maybe in live..?

###### * (I received questions about how to know when to put a component to `views` folder and when to `components`. Well, if your component is reused, say on different pages/views or other components than put it in `components` folder.
###### ** Yeah, I know about stuff like `v-bind="$attrs"` let me keep this article shorter? :)

## 

###### Cover photo: https://blog.pusher.com/building-external-modules-vuejs/