DEV Community

Cover image for Vue.js Components Communication Patterns (without Vuex) - Part 2
Chris Y.
Chris Y.

Posted on

Vue.js Components Communication Patterns (without Vuex) - Part 2

$parent and $children patterns

In Part 1 of this series, we introduced two patterns that work perfectly in a two-level component hierarchy, but what about a three-level or even four or five-level hierarchy?
Now following the starting examples of Part 1,
let's add a new component GrandchildA, and here is the initial state of the three components:

Image description

Parent has a ChildA component that gets an input event bound onto its tag. This is the "custom v-model" pattern discussed in Part 1.

Image description

Similar to Parent, ChildA now has a GrandchildA component that gets an input event bound onto its tag, and it passes the desserts data it receives from Parent into GrandchildA. Notice the watch function for its prop value at line 38, this is to make sure whenever the prop changes, ChildA.desserts will get the latest value.

Also, GrandchildA will pass its data to ChildA, and ChildA will pass it back to Parent, as seen in lines 43 - 46.

Image description

GrandchildA has the same settings as ChildA in Part 1, it has a button where we can add a new dessert.
In the event handler function handleUpdate, it will use $emit to trigger the input event bound onto it in ChildA, and pass the new data as the argument.

Here is the current view:

Image description

Now if the user clicks the Update button on GrandchildA, the view becomes:

Image description

GrandchildA sends the updated desserts to ChildA by this.$emit('input', this.desserts), and ChildA does the same and passes the data to Parent, Parent updates its this.desserts using the new value, and passes it down to ChildA as a prop. ChildA is watching the prop value change, so it will update its this.desserts, and this.desserts is passed down to GrandchildA as a prop.

So in order for GrandchildA to communicate with Parent, it must go through the middle man ChildA. How about now we add a GrandGrandchild component? It will follow the same approach, and both ChildA and GrandchildA will become the middle man. When it comes to a multi-level hierarchy, we can repeat the two patterns from Part 1 in each descendant component, but there is a better way.

$parent pattern

Now let's modify GrandchildA.handleUpdate():

Image description

Thanks to the exquisite design of Vue, we don't really need to trigger the input event on GrandchildA and then execute the callback function in ChildA. Instead, in GrandchildA we can directly trigger the input event on ChildA using this.$parent to execute the callback function in Parent, because GrandchildA.$parent = ChildA. Super simple, isn't it?

Since we don't need ChildA to do the middle man work anymore, now ChildA can be very simple:

Image description

ChildA becomes to only receive a prop and pass it to GrandchildA. If we click the Update button now, it works the same:

Image description

The new desserts data is updated from GrandchildA directly to Parent, then passed down to ChildA and GrandchildA.

$children pattern

In a Vue component tree, there is $parent, and of course, there is $children as well. Let's see an example of $children. We will leave GrandchildA as is, while in ChildA, now we bind a new event named show:alert onto the GrandchildA tag:

Image description

And the event callback function is handleShowAlert which will show an alert. Now in Parent, let's add a new button:

Image description

When clicking the button, we want to trigger the show:alert event on GrandchildA, which will, in turn, execute ChildA.handleShowAlert() to show the alert. This is achieved using:

this.$children[0].$children[0].$emit('show:alert');
Enter fullscreen mode Exit fullscreen mode

Because $children is an array of VueComponent instances and there is only one child for both Parent and ChildA, we can use $children[0].
Now if the user clicks the button:

Image description

An alert is shown as expected.

Conclusion

For a multi-level hierarchy of components, the "$parent and $children" patterns are suitable as they can reduce the level-by-level data passing between components. But if there are too many levels, then we would have to do something like this:

this.$parent.$parent.$parent.$parent.$emit('input', this.desserts);
Enter fullscreen mode Exit fullscreen mode

Also, a parent component can have many children components, and each child component can have its many children components. How can we pinpoint a specific child component in the $children array? This question will lead us to Part 3 of this series where we will look to solve it.

Here are all the articles in this series:

Vue.js Components Communication Patterns (without Vuex) - Part 1

Vue.js Components Communication Patterns (without Vuex) - Part 2

Vue.js Components Communication Patterns (without Vuex) - Part 3

Vue.js Components Communication Patterns (without Vuex) - Part 4

Vue.js Components Communication Patterns (without Vuex) - Part 5

Vue.js Components Communication Patterns (without Vuex) - Part 6

Vue.js Components Communication Patterns (without Vuex) - Part 7

Discussion (0)