Transfer Data Between Components in Vue
Transfer Data Between Components in Vue

In this video you will learn how parent and child components can communicate with each other.

In previous videos we created UsersList component. It works nicely but let's discuss the case where we want to create a sharable component between pages. Let's say we have a page with the list of favorite users and the page with the list of last added users. Actually would be nice to create single component UsersList which renders users and doesn't know anything about from where the data of users are coming. Then each page can get data from API for example and use our sharable UsersList component just to add and remove data.

First let's make our UsersList sharable component. For this we need to create other component which will be it's parent and will be rendered on Users page.

src/views/Users.vue

<template>
  <div>
    Users
  </div>
</template>

<script>
export default {
  name: "Users",
};
</script>

Now we need to render this component instead of UsersList.

router/index.js

{
  path: "/users",
  name: "users",
  component: Users,
},

As you can see in browser, everything is working as expected.

Now we want to do UsersList sharable. And actually there is a special folder for it. If we want to reuse the component between different pages then we put it in src/components folder. Let's copy it now.

It's time to render our sharable component UsersList inside Users component. We can't do it just like plain html. We need first to defined UsersList as a child component of Users.

<script>
import UsersList from "@/components/UsersList";

export default {
  name: "Users",
  components: { UsersList },
};
</script>

So we imported UsersList component here and added it to the property components. The important part here is @ symbol in the import. It's a special alias inside Webpack which means for us src folder. This helps us to avoid relative paths.

Now we can render UsersList component inside our template.

<div>
  Users
  <users-list></users-list>
</div>

As you can see I used here the name of the component but with dashes. You can also just write it camel case. Both variants are correct.

Let's check that everything is working. Now our UsersList is also rendered but it's a sharable component.

What we need to do know is pass data inside UsersList from parent. Because as I said previously we need to have different data in different places. So actually UsersList component doesn't need to know anything about rendering the data.

So I will simply copy users array in parent.

export default {
  name: "Users",
  components: { UsersList },
  data() {
    return {
      users: [
        {
          id: "1",
          name: "User 1",
          age: 20,
        },
        {
          id: "2",
          name: "User 2",
          age: 25,
        },

        {
          id: "3",
          name: "User 3",
          age: 30,
        },
      ],
    };
  },
};

Now let's pass this data inside our component. In Vue we are doing it through props. Which means each component can define what properties we need to give from outside in order to use it.

export default {
  name: "UsersList",
  props: {
    users: {
      type: Array,
      required: true
    }
  }
}

As you can see props is an object and we define that we are waiting to get users which is required array. Now let's pass users inside.

<users-list :users="users"></users-list>

So here we used property bind to pass data inside our component. And this is how we are passing data from parent to child in Vue.

As you can see in browser everything is working as expected.

Now we want to move remove and add user outside of UsersList. Why? Because maybe we want to do additionaly API request to save or remove user. Or something else. If we remove this methods outside then our UsersList list is completely sharable and doesn't change the data inside.

So first I will completely copy removeUser and addUser to the parent. Now in removeUser I just want to emit an event on which parent can react. So we simply want to say "Please remove a user with ID".

removeUser(id) {
  this.$emit("removeUser", id);
},

So here we used special syntax $emit. The first parameter is a name and second is our data.
And now in parent we can react on this event.

<users-list :users="users" @removeUser="removeUser"></users-list>

Here we have the same thing. It's just event binding like we did previously with click but just with custom event.

As you can see in browser everything is working as previously but now we don't have this removeUser implementation inside.

Let's do the same with addUser.

addUser() {
  this.$emit("addUser", this.newUserName);
},
addUser(newUserName) {
  const uniqueId = Math.random().toString(16);
  const newUser = {
    id: uniqueId,
    name: newUserName,
    age: 30,
  };
  this.users.push(newUser);
},

As you can see everything is working as previously but now we moved our function addUser to the parent. Now our UsersList doesn't do anything except of rendering the data and reacting to user events. All business logic is outside.

In this video you learned how to build sharable component and how parent child components can communicate between using props and emits.

If "Vue for beginners" is too easy for you go check my advanced course about Vue which is going 10 course and where we are creating together the application from empty folder to fully finished application.

📚 Source code of what we've done