DEV Community

Cover image for Getting Started to Vue 3
Patricia Namoro
Patricia Namoro

Posted on • Edited on

Getting Started to Vue 3

Install NodeJS
https://nodejs.org/en/download/

Install Git
https://git-scm.com/downloads

Install Vue CLI
npm install -g @vue/cli

Install Vuex
npm install vuex --save

Install Vue Router
npm install vue-router --save

Create a Project
vue create vue-workshop

Dialog Option Selection:

  • Default (Vue 2)
  • Default (Vue 3)

Note: Use Vue 2 if you plan to use Vuex and/or Vue Router

Run Project
cd vue-workshop

Edit package.json (line 6)
vue-cli-service serve --host localhost

npm run serve

VueJS Basics

Reactivity

Reactivity.vue

<template>
  <div class="pad-top">
    The time is: {{ date }}
  </div>
</template>

<script>
export default {
  name: "Reactivity",
  data() {
    return {
      date: null,
    }
  },
  mounted() {
    setInterval(() => {
      this.date = (new Date()).toLocaleString()
    }, 1000);
  },
}
</script>

<style scoped>
</style>
Enter fullscreen mode Exit fullscreen mode

Input Binding

InputBinding.vue

<template>
  <div class="pad-top">
    <span>Type your name:</span>
    <input
       class="margin-right"
       v-model="name"
    />
  </div>
  <div class="pad-top">
    Your name is {{ name }}!
  </div>
</template>

<script>
export default {
  name: "InputBinding",
  data() {
    return {
      name: ‘’,
    }
  },
}
</script>

<style scoped>
.pad-top {
  padding-top: 15px;
}
</style>
Enter fullscreen mode Exit fullscreen mode

Element Visibility based on Input Binding

InputBindingVisibility.vue

<template>
  <div class="pad-top">
    <span>Type your name:</span>
    <input
       class="margin-right"
       v-model="name"
    />
  </div>
  <div class="pad-top" v-show="name !== ''">
    Your name is {{ name }}!
  </div>
</template>

<script>
export default {
  name: "InputBindingVisibility",
  data() {
    return {
      name: ‘’,
    }
  },
}
</script>

<style scoped>
.pad-top {
  padding-top: 15px;
}
</style>
Enter fullscreen mode Exit fullscreen mode

Event Handling

EventHandling.vue

<template>
  <div>
    <button @click="toggleMe">Click me!</button>
  </div>
</template>

<script>
export default {
  name: "EventHandling",
  methods: {
    toggleMe() {
      alert(I was clicked!);
    }
  }
}
</script>

<style scoped>
</style>

Enter fullscreen mode Exit fullscreen mode

Conditional Rendering

ConditionalRendering.vue

<template>
  <div class="pad-top">
    <button @click="toggleMe">Click me!</button>
  </div>
  <div class="pad-top" v-if="toggleDiv">
    HOLA!
  </div>
</template>

<script>
export default {
  name: "ConditionalRendering",
  data() {
    return {
      toggleDiv: false,
    }
  },
  methods: {
    toggleMe() {
      this.toggleDiv = !this.toggleDiv
    }
  }
}
</script>

<style scoped>
.pad-top {
  padding-top: 15px;
}
</style>



Enter fullscreen mode Exit fullscreen mode

List Rendering

ListRendering.vue

<template>
  <div>
    <div>
      Things to do:
    </div>
    <div>
      <ul>
        <li v-for="listItem in sampleList" :key="listItem.text">
          {{ listItem.text }}
        </li>
      </ul>
    </div>
  </div>
</template>

<script>
export default {
  name: "ListRendering",
  data() {
    return {
      sampleList: [
        { text: 'Eat' },
        { text: 'Sleep' },
        { text: 'Be awesome' }
      ]
    }
  },
}
</script>

<style scoped>
</style>

Enter fullscreen mode Exit fullscreen mode

Vue Component Lifecycle

Link

Vue Lifecycle Hooks

Link

Vue Lifecycle Hooks

Hooks.vue
<template>
  <div>
    <h1>Hello!</h1>
  </div>
</template>

<script>
export default {
  name: "Hooks",
  beforeCreate() {
    // Called after the instance has been initialized
    alert(beforeCreate triggered.);
  },
  created() {
    // Called after the instance is created
    alert(created triggered.);
  },
  beforeMount() {
    // Called right before the mounting begins
    alert(beforeMount triggered.);
  },
  mounted() {
    // Called after the instance has been mounted
    alert(mounted triggered.);
  },
  beforeUpdate() {
    // Called when data changes, before the DOM is patched
    alert(beforeUpdate triggered.);
  },
  updated() {
    /**
     * Called after a data change causes the virtual DOM 
     * to be re-rendered and patched.
     */
    alert(updated triggered.);
  },
  beforeUnmount() {
    // Called right before a component instance is unmounted
    alert(beforeUnmount triggered.);    
  },
  unmounted() {
    // Called after a component instance has been unmounted
    alert(unmounted triggered.);
  }
}
</script>

<style scoped>
</style>

Enter fullscreen mode Exit fullscreen mode

Computed vs Methods: What to use?

Computed Properties:
cached based on their reactive dependencies
only re-evaluates when some of its reactive dependencies have changed

Methods:
no caching occurs
will always run the function whenever a re-render happens

TL:DR
Use Computed Properties when functionality reacts to DOM changes
Use Methods when functionality is triggered by a user event

ComputedProperties.vue

<template>
  <div>
    <div>Do I have things to do? {{ thingsToDo }}</div>
    <div>Things to do:</div>
    <ul>
      <li v-for="listItem in sampleList" :key="listItem.text">
        {{ listItem.text }}
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  name: "ComputedProperties",
  computed: {
    thingsToDo() {
      /**
 * This statement’s result is cached and will only
       * re-evaluate when sampleList changes content,
       * saving computational power.
       */
      return this.sampleList.length > 0 ? 'Yes' : 'No'
    }
  },
  data() {
    return {
      sampleList: [
        { text: 'Eat' },
        { text: 'Sleep' },
        { text: 'Be awesome' }
      ]
    }
  },
}
</script>

<style scoped>
</style>

Enter fullscreen mode Exit fullscreen mode

v-if vs v-show: What to use?

v-if:
is "real" conditional rendering
event listeners and child components are properly destroyed and re-created
DOM elements are properly destroyed and re-created
is “lazy”; i.e. DOM elements WILL NOT render unless condition is true on first load

v-show:
is always rendered regardless of condition
uses CSS to toggle elements ON and OFF
event listeners and child components stay rendered regardless of condition
DOM elements stay rendered when toggling ON and OFF

TL:DR

Use v-show if you need to toggle something very often
Use v-if if the condition is unlikely to change at runtime

ConditionalSample.vue

<template>
  <div>
    <div>
      <button @click=toggleContent>Click Me!</button>
    </div>
    <div v-if=showContent>
      <span>I am v-if rendered!</span>
    </div>
    <div v-show=showContent>
      <span>I am v-show rendered</span>
    </div>
  </div>
</template>

<script>
export default {
  name: "ConditionalSample",
  data() {
    return {
      showContent: false
    }
  },
  methods: {
    toggleContent() {
      this.showContent = !this.showContent
    }
  }
}
</script>

<style scoped>
</style>

Enter fullscreen mode Exit fullscreen mode

Components

When to use components:
Repeated functionality across multiple pages
Decoupling of long, mangled, spaghetti codebase

Component Data Flow:
To pass data from parent component to child component, use props
To pass data from child component back to parent component, use emit

How to use components

ParentComponent.vue

<template>
  <div>
    <div>Hi! I am a parent component.</div>
    <div>
      <ChildComponent />
    <div>
  <div>
</template>

<script>
import ChildComponent from ./ChildComponent;

export default {
  name: ParentComponent,
  components: {
    ChildComponent
  }
}
</script>

<style scoped>
</style>

Enter fullscreen mode Exit fullscreen mode

ChildComponent.vue

<template>
  <div>
    <div>Hi! I am a child component. {{ message }}</div>
  <div>
</template>

<script>
export default {
  name: ChildComponent,
  data() {
    return {
      message: yay!
    }
  }
}
</script>

<style scoped>
</style>

Enter fullscreen mode Exit fullscreen mode

How to pass data to child component

ParentComponent.vue

<template>
  <div>
    <div>Hi! I am a parent component.</div>
    <div>
      <ChildComponent :message=message/>
    <div>
  <div>
</template>

<script>
import ChildComponent from ./ChildComponent;

export default {
  name: ParentComponent,
  components: {
    ChildComponent
  },
  data() {
    return {
      message: yay!
    }
  }
}
</script>

<style scoped>
</style>

Enter fullscreen mode Exit fullscreen mode

ChildComponent.vue

<template>
  <div>
    <div>Hi! I am a child component. {{ message }}</div>
  <div>
</template>

<script>
export default {
  name: ChildComponent,
  props: [
    'message'
  ],
}
</script>

<style scoped>
</style>

Enter fullscreen mode Exit fullscreen mode

How to pass data to parent component

ParentComponent.vue

<template>
  <div>
    <div>Hi! I am a parent component.</div>
    <div>
      <ChildComponent
        :message=message
        @pass-message=parseChildMessage
      />
    <div>
  <div>
</template>

<script>
import ChildComponent from ./ChildComponent;

export default {
  name: ParentComponent,
  components: {
    ChildComponent
  },
  data() {
    return {
      message: yay!
    }
  },
  methods: {
    parseChildMessage(message) {
      alert(Yay! Child component says  + message);
    }
  }
}
</script>

<style scoped>
</style>

Enter fullscreen mode Exit fullscreen mode

ChildComponent.vue

<template>
  <div>
    <div>Hi! I am a child component. {{ message }}</div>
    <div>
      <button @click=sendBack>Click Me!</button>
    </div>
  <div>
</template>

<script>
export default {
  name: ChildComponent,
  props: [
    'message'
  ],
  methods: {
    sendBack() {
      this.$emit(passMessage, Hello!);
    }
  }
}
</script>

<style scoped>
</style>


Enter fullscreen mode Exit fullscreen mode

Vuex

What it is:
a state-management pattern + library
a centralized store for all components
has rules ensuring that the state can only be mutated in a predictable fashion
used in building large-scale Single-Page Applications

Vuex Core Concepts

State
Vuex uses a single state tree
a single object contains all application-level state
serves as the "single source of truth."
Vuex follows the same rules as the data in a Vue instance
reactive

Getters
considered as computed properties for stores
result is cached based on its dependencies
will only re-evaluate when some of its dependencies have changed

Mutations
the only way to actually change state in a Vuex store
mutations are very similar to events
each mutation has a string type and a handler.
handler function is where actual state modifications are performed
handler function receives state as the first argument

Actions
are similar to mutations, with key differences
actions commit mutations instead of mutating the state
actions can contain arbitrary asynchronous operations
mutations have to be synchronous, while actions does not have to be

Modules

allows Vuex to divide store into modules
each module can contain its own state, mutations, actions, getters

References:
https://vuex.vuejs.org/guide/state.html
https://vuex.vuejs.org/guide/getters.html
https://vuex.vuejs.org/guide/mutations.html
https://vuex.vuejs.org/guide/actions.html
https://vuex.vuejs.org/guide/modules.html

How to Setup Vuex in a Project

src/store/index.js

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

const store = new Vuex.Store({})

export default store


src/main.js
import Vue from 'vue'
import App from './App.vue'
import store from './store/index'

Vue.config.productionTip = false

new Vue({
  render: h => h(App),
  store
}).$mount('#app')


Enter fullscreen mode Exit fullscreen mode

How to add store state

src/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

const store = new Vuex.Store({
  state: {
    todoList: [
      { value: Code }
    ]
  },
})

export default store
Enter fullscreen mode Exit fullscreen mode

SampleComponent.vue

<template>
  <div>
    <tr v-for="(item, index) in todoList" :key="index">
      <td>{{ item.value }}</td>
    </tr>
  </div>
</template>

<script>
export default {
  name: SampleComponent,
  computed: {
    todoList() {
      return this.$store.state.todoList
    }
  }
}
</script>

<style scoped>
</style>
Enter fullscreen mode Exit fullscreen mode

How to add store getters

src/store/index.js

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

const store = new Vuex.Store({
  state: {
    todoList: [
      { value: Code }
    ]
  },
  getters: {
    todoList: state => {
      return state.todoList
    }
  },
})

export default store


Enter fullscreen mode Exit fullscreen mode

SampleComponent.vue

<template>
  <div>
    <tr v-for="(item, index) in todoList" :key="index">
      <td>{{ item.value }}</td>
    </tr>
  </div>
</template>

<script>
export default {
  name: SampleComponent,
  computed: {
    todoList() {
      return this.$store.getters.todoList
    }
  }
}
</script>

<style scoped>
</style>
Enter fullscreen mode Exit fullscreen mode

How to add store mutations

src/store/index.js

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

const store = new Vuex.Store({
  state: {
    todoList: [
      { value: Code }
    ]
  },
  getters: {
    todoList: state => {
      return state.todoList
    }
  },
  mutations: {
    addTodoItem(state, value) {
      state.todoList.push({value: value})
    },
    removeTodoItem(state, value) {
      state.todoList.splice(value, 1)
    }
  }
})

export default store


Enter fullscreen mode Exit fullscreen mode

SampleComponent.vue

<template>
  <div>
    <div>
      <span>Add Item: </span>
      <input v-model="todoInput" />
      <button @click="addItem">Add Item</button>
    </div>
    <div>
      <tr v-for="(item, index) in todoList" :key="index">
        <td>
          <button @click="removeItem(index)">X</button>
        </td>
        <td>{{ item.value }}</td>
      </tr>
    <div>
  </div>
</template>

<script>
export default {
  name: SampleComponent,
  computed: {
    todoList() {
      return this.$store.getters.todoList
    }
  },
  data() {
    return {
      todoInput: ‘’
    }
  },
  methods: {
    addItem() {
      this.$store.commit('addTodoItem', this.todoInput)
    },
    removeItem(index) {
      this.$store.commit(removeTodoItem, index)
    }
  }
}
</script>

<style scoped>
</style>

Enter fullscreen mode Exit fullscreen mode

How to add store actions

src/store/index.js

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

const store = new Vuex.Store({
  state: {
    todoList: [
      { value: Code }
    ]
  },
  getters: {
    todoList: state => {
      return state.todoList
    }
  },
  mutations: {
    addTodoItem(state, value) {
      state.todoList.push({value: value})
    },
    removeTodoItem(state, value) {
      state.todoList.splice(value, 1)
    }
  },
  actions: {
    addItem (context, item) {
      context.commit('addTodoItem', item)
    },
    removeItem(context, itemIndex) {
      context.commit('removeTodoItem', itemIndex)
    }
  }
})

export default store


Enter fullscreen mode Exit fullscreen mode

SampleComponent.vue

<template>
  <div>
    <div>
      <span>Add Item: </span>
      <input v-model="todoInput" />
      <button @click="addItem">Add Item</button>
    </div>
    <div>
      <tr v-for="(item, index) in todoList" :key="index">
        <td>
          <button @click="removeItem(index)">X</button>
        </td>
        <td>{{ item.value }}</td>
      </tr>
    <div>
  </div>
</template>

<script>
export default {
  name: SampleComponent,
  computed: {
    todoList() {
      return this.$store.getters.todoList
    }
  },
  data() {
    return {
      todoInput: ‘’
    }
  },
  methods: {
    addItem() {
      this.$store.dispatch('addItem', this.todoInput)
    },
    removeItem(index) {
      this.$store.dispatch(removeItem, index)
    }
  }
}
</script>

<style scoped>
</style>


Enter fullscreen mode Exit fullscreen mode

How to setup store into modules

src/store/index.js

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

const moduleA = {
  state: () => ({
    todoList: [
      { value: Code }
    ]
  }),
  getters: {
    todoList: state => {
      return state.todoList
    }
  },
  mutations: {
    addTodoItem(state, value) {
      state.todoList.push({value: value})
    },
    removeTodoItem(state, value) {
      state.todoList.splice(value, 1)
    }
  },
  actions: {
    addItem (context, item) {
      context.commit('addTodoItem', item)
    },
    removeItem(context, itemIndex) {
      context.commit('removeTodoItem', itemIndex)
    }
  }
}

const store = new Vuex.Store({
  modules: {
    moduleA: moduleA
  } 
})

export default store
Enter fullscreen mode Exit fullscreen mode

SampleComponent.vue

<template>
  <div>
    <div>
      <span>Add Item: </span>
      <input v-model="todoInput" />
      <button @click="addItem">Add Item</button>
    </div>
    <div>
      <tr v-for="(item, index) in todoList" :key="index">
        <td>
          <button @click="removeItem(index)">X</button>
        </td>
        <td>{{ item.value }}</td>
      </tr>
    <div>
  </div>
</template>

<script>
export default {
  name: SampleComponent,
  computed: {
    todoList() {
      return this.$store.getters.todoList
    }
  },
  data() {
    return {
      todoInput: ‘’
    }
  },
  methods: {
    addItem() {
      this.$store.dispatch('addItem', this.todoInput)
    },
    removeItem(index) {
      this.$store.dispatch(removeItem, index)
    }
  }
}
</script>

<style scoped>
</style>

Enter fullscreen mode Exit fullscreen mode

Vue Router

What it is:
a routing mechanism for switching components
used in building Single Page Applications
useful for changing components using URL paths

Reference: https://router.vuejs.org/guide/#html

How to Setup Vue Router in a Project

src/routes/index.js

import Vue from 'vue'
import VueRouter from 'vue-router'
import HelloWorld from './../components/HelloWorld.vue'

Vue.use(VueRouter)

const routes = [
  {
    path: '/', 
    component: HelloWorld,
  },
]

const router = new VueRouter({
  routes
})

export default router


Enter fullscreen mode Exit fullscreen mode

src/main.js

import Vue from 'vue'
import App from './App.vue'
import router from './routes/index.js'

Vue.config.productionTip = false

new Vue({
  render: h => h(App),
  router
}).$mount('#app')

Enter fullscreen mode Exit fullscreen mode

src/App.vue

<template>
  <div id="app">
    <img alt="Vue logo" src="./assets/logo.png">
    <div>
      <router-link :to="{ path: '/'}">Home</router-link>
    </div>
    <router-view />
  </div>
</template>

<script>
export default {
  name: 'App',
}
</script>

<style scoped>
</style>


Enter fullscreen mode Exit fullscreen mode

How to add routes

src/routes/index.js

import Vue from 'vue'
import VueRouter from 'vue-router'
import HelloWorld from './../components/HelloWorld.vue'
import TodoComponent from './../components/TodoComponent.vue'

Vue.use(VueRouter)

const routes = [
  {
    path: '/', 
    component: HelloWorld,
  },
  {
    path: '/todolist', 
    component: TodoComponent
  },
]

const router = new VueRouter({
  routes
})

export default router


Enter fullscreen mode Exit fullscreen mode

src/components/TodoComponent.vue

<template>
  <div>
    Todo Component
  </div>
</template>

<script>
export default {
    name: 'TodoComponent'
}
</script>

<style scoped>
</style>


Enter fullscreen mode Exit fullscreen mode

src/App.vue

<template>
  <div id="app">
    <img alt="Vue logo" src="./assets/logo.png">
    <div>
      <router-link :to="{ path: '/'}">Home</router-link>
      <router-link 
        :to="{ path: '/todolist'}"
      >
        TodoComponent
      </router-link>
    </div>
    <router-view />
  </div>
</template>

<script>
export default {
  name: 'App',
}
</script>

<style scoped>
</style>


Enter fullscreen mode Exit fullscreen mode

Dynamic Routes

What it is:
useful for components which depends on certain parameters before rendering
allows passing values in between routes

How to add dynamic routes

To see it in action, type the following URL:
http://localhost:8080/#/person/1

src/routes/index.js

import Vue from 'vue'
import VueRouter from 'vue-router'
import HelloWorld from './../components/HelloWorld.vue'
import TodoComponent from './../components/TodoComponent.vue'
import PersonComponent from './../components/PersonComponent.vue'

Vue.use(VueRouter)

const routes = [
  {
    path: '/', 
    component: HelloWorld,
  },
  {
    path: '/todolist', 
    component: TodoComponent
  },
  {
    path: /person/:id,
    component: PersonComponent
  }
]

const router = new VueRouter({
  routes
})

export default router


Enter fullscreen mode Exit fullscreen mode

src/components/PersonComponent.vue

<template>
  <div>
    Person Component
    {{ $route.params.id }}
  </div>
</template>

<script>
export default {
    name: 'PersonComponent'
}
</script>

<style scoped>
</style>

Enter fullscreen mode Exit fullscreen mode

Programmatic Navigation

When to use:
route needs to be navigated using function
route requires dynamic parameters
route needs to be navigated after a certain process occurs

**Reference: **https://router.vuejs.org/guide/essentials/navigation.html

How to programmatically navigate a route

ProgrammaticRouting.vue

<template>
  <div>
    <button @click=navigate>Navigate to somewhere</button>
  </div>
</template>

<script>
export default {
  name: 'ProgrammaticRouting',
  methods: {
    navigate() {
      // The path must be the same as the path declared in routes
      this.$router.push({path: somewhere})
    }
  }
}
</script>

<style scoped>
</style>


Enter fullscreen mode Exit fullscreen mode

Top comments (2)

Collapse
 
citronbrick profile image
CitronBrick

It'll make a great difference if you could format your code.

Use "

html" and "

javascript".

You can also format npm commands as code blocks.

Collapse
 
gitpat749 profile image
Patricia Namoro

oh yeah thanks will apply these changes!