본문 바로가기
Web/JavaScript

[Vue3] Component Usage

by llHoYall 2021. 6. 20.

In this posting, we'll learn about component usage on Vue.

Most projects don't consist of a single file.

So, we usually create several components and consist of these components in a project.

Create a Project

First of all, let's create a simple project for testing.

2021.06.02 - [Web/JavaScript] - [Vue] Getting Started with Vue3 + TypeScript + TailwindCSS

Basic Usage

This is the default folder structure of our project.

Let's open the App.vue file.

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

<script lang="ts">
import { defineComponent } from "vue";
import HelloWorld from "./components/HelloWorld.vue";

export default defineComponent({
  name: "App",
  components: {
    HelloWorld,
  },
});
</script>

If you want to use a component, you need to import components first.

As you can see, this code also imports HelloWorld.

Next, it registers the HelloWorld component into the components property.

Finally, if you look at the template area, it is used with the msg property.

 

Next, let's open the HelloWorld.vue file.

<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
    ...
  </div>
</template>

<script lang="ts">
import { defineComponent } from "vue";

export default defineComponent({
  name: "HelloWorld",
  props: {
    msg: String,
  },
});
</script>

As you can see from the code, communication between components can be done through props.

i.e., a parent component sends data to a child component through props.

Global Component

Let's change the HelloWorld component to a global component.

If a component is changed to a global component, it can be called anywhere in the code without import.

 

Let's open the main.ts file.

Every global component should be located in this file.

import HelloWorld from "./components/HelloWorld.vue";

const app = createApp(App);

app.component("HelloWorld", HelloWorld);

app.mount("#app");

Import a component globally and add it as a global component.

 

Now, open App.vue file.

And, remove this code because it is required no longer.

import { defineComponent } from "vue";
// import HelloWorld from "./components/HelloWorld.vue";

export default defineComponent({
  name: "App",
  // components: {
  //   HelloWorld,
  // },
});

We can use the HelloWorld component without import now.

This is the power of the global component.

Communication between Components

props

If you send data with props, it would be a string type.

 

components/HelloWorld.vue

<template>
  ...
  <h2 class="mt-8 mb-2 text-xl font-medium text-green-600">props</h2>
  <div class="text-center">msg1: {{ msg1 }}, Types: {{ typeof msg1 }}</div>
  <div class="text-center">msg2: {{ msg2 }}, Types: {{ typeof msg2 }}</div>
  ...
</template>

<script lang="ts">
  ...
  props: {
    msg1: Number,
    msg2: Number,
  },
});
</script>

App.vue

<HelloWorld msg1="1" :msg2="1" />

 

Look at this result.

If you want to send data to other types like Number, Boolean, Array, or Object form, you should use v-bind.

Props Validation

You can use props with several properties.

 

components/HelloWorld.vue

props: {
  prop1: [String, Number],
  prop2: { type: String, required: true },
  prop3: { type: Number, default: 7 },
  prop4: {
    type: Object,
    default: function () {
      return { value: "hello" };
    },
  },
  prop5: {
    validator: function (value: string) {
      return ["success", "failure"].indexOf(value) !== -1;
    },
  },
},

prop1 => It can have multiple types.

<HelloWorld prop1="2" />
<HelloWorld :prop1="2" />
<HelloWorld :prop1="false" />

The first two cases are good, but the last case is bad.

prop2 => It must be sent from a parent component.

prop3 => It has default value. It is set when data is not passed from a parent component.

prop4 => The default value of Object or Array has to be returned from a factory function.

prop5 => It should have a value "success" or "failure".

<HelloWorld prop5="error" />

$refs

A parent component can access the child component through the $refs.

 

components/HelloWorld.vue

<template>
  ...
  <h2 class="mt-8 mb-2 text-xl font-medium text-green-600">
    event from the parent
  </h2>
  <button @click="fromParent" ref="btnFromParent" class="btn">Click</button>
</template>

<script lang="ts">
...
  methods: {
    fromParent: function () {
      console.log("This event is from the parent");
    },
  },
});
</script>

App.vue

<template>
  ...
  <HelloWorld ref="child_component/>
  <button @click="sendEventFromParent" class="btn">From Parent (Event)</button>
</template>

<script lang="ts">
  ...
  methods: {
    sendEventFromParent: function () {
      (
        (this.$refs.child_component as InstanceType<typeof Communication>).$refs
          .btnFromParent as HTMLButtonElement
      ).click();
    },
  },
});
</script>

 

If you click the button "From Parent (Event)", the parent component can call the child component's function through $refs with ref attribute.

sendEventFromParent: function () {
  // (
  //   (this.$refs.child_component as InstanceType<typeof Communication>).$refs
  //     .btnFromParent as HTMLButtonElement
  // ).click();
  (
    this.$refs.child_component as InstanceType<typeof Communication>
  ).fromParent();
},

Or a parent component can call directly like the above.

 

A parent component can access data of child components in the same say.

 

components/HelloWorld.vue

<template>
  ...
  <div>{{ child_data }}</div>
</template>

<script lang="ts">
  ...
    data: function () {
    return {
      child_data: "Hello",
    };
  },
});
</script>

App.vue

<template>
  ...
  <button @click="sendDataFromParent" class="mt-4 btn">Parent (Data)</button>
</template>

<script lang="ts">
  ...
  methods: {
    sendDataFromParent: function () {
      (
        this.$refs.child_component as InstanceType<typeof Communication>
      ).child_data = "Modified by Parent";
    },
  },
});
</script>

If you click the button "Parent (Data)", the child's data will be changed.

$emit

Use $emit to pass events from a child component to a parent component.

 

components/HelloWorld.vue

<template>
  ...
  <button @click="toParent" class="btn">Click</button>
</template>

<script lang="ts">
  ...
  methods: {
    toParent: function () {
      this.$emit("send-event", "This event is from child");
    },
  },
});
</script>

I made a button to send an event to a parent component.

 

App.vue

<template>
  ...
  <HelloWorld @send-event="sendEventFromChild" />
</template>

<script lang="ts">
...
  methods: {
    sendEventFromChild: function (msg: string) {
      console.log(msg);
    },
  },
});
</script>

If you click the button, the child component sends an event with a message to a parent component.

And parent component's method is called by a child component.

Create Our Own Component

Now, let's create our own component.

This component is about a to-do list.

 

components/ToDoItem.vue

<template>
  <li :class="{ complete: item.complete }" @click="toggle">{{ item.title }}</li>
</template>

<script lang="ts">
import { defineComponent } from "vue";

export default defineComponent({
  name: "ToDoItem",
  props: {
    item: Object,
    index: Number,
  },
  methods: {
    toggle() {
      this.$emit("toggle", this.index);
    },
  },
});
</script>

<style>
.complete {
  text-decoration: line-through;
}
</style>

Our component displays to-do items.

It gets data from its parent through props and sends data to its parent through $emit.

 

App.vue

<template>
  ...
  <hr />
  <h1>ToDo List</h1>
  <ol>
    <ToDoItem
      v-for="(item, index) in todoItems"
      :key="index"
      :item="item"
      :index="index"
      @toggle="toggle"
    />
  </ol>
</template>

<script lang="ts">
import { defineComponent } from "vue";
import ToDoItem from "./components/ToDoItem.vue";

export default defineComponent({
  name: "App",
  components: {
    ToDoItem,
  },
  data: function () {
    return {
      todoItems: [
        { title: "ToDo Item1", complete: false },
        { title: "ToDo Item2", complete: false },
        { title: "ToDo Item3", complete: false },
      ],
    };
  },
  methods: {
    toggle(index: number) {
      this.todoItems[index].complete = !this.todoItems[index].complete;
    },
  },
});
</script>

The parent sends the data to its children.

Children render themselves with the data from its parent.

And the click event emits to its parent.

This is so easy example.

Let's test this!

Conclusion

Now, we learned how to make a component, how to use it, and how to communicate with them.

'Web > JavaScript' 카테고리의 다른 글

[Vue3] Send Data from Ancestor Component using Provide and Inject  (0) 2021.06.20
[Vue3] Slot (v-slot) Usage  (0) 2021.06.20
[Vue3] Vue-Router Usage  (0) 2021.06.18
[Vue3] Lifecycle  (0) 2021.06.16
[Vue3] Computed Property and Watcher  (0) 2021.06.12

댓글