<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Chris Y.</title>
    <description>The latest articles on DEV Community by Chris Y. (@chris_y).</description>
    <link>https://dev.to/chris_y</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F760035%2F0eaab2e8-a923-4d91-8e82-897b868b445c.png</url>
      <title>DEV Community: Chris Y.</title>
      <link>https://dev.to/chris_y</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/chris_y"/>
    <language>en</language>
    <item>
      <title>Vue.js Components Communication Patterns (without Vuex) - Part 3</title>
      <dc:creator>Chris Y.</dc:creator>
      <pubDate>Tue, 23 Nov 2021 12:29:41 +0000</pubDate>
      <link>https://dev.to/chris_y/vuejs-components-communication-patterns-without-vuex-part-3-2ng0</link>
      <guid>https://dev.to/chris_y/vuejs-components-communication-patterns-without-vuex-part-3-2ng0</guid>
      <description>&lt;p&gt;&lt;strong&gt;&lt;em&gt;Upward-broadcast and Downward-broadcast patterns&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In &lt;a href="https://csdigitalnomad.medium.com/vue-js-components-communication-patterns-without-vuex-part-2-7f9c0bc132a2"&gt;Part 2&lt;/a&gt; of this series, we used the "$parent" and the "$children" patterns to enable components to communicate in a three-level hierarchy. Towards the end, we had a question in mind for an even more complex hierarchy of components, e.g. what if there are ten levels of components? Do we need to do something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;anyEvent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let alone the children components can be hard to track.&lt;/p&gt;

&lt;p&gt;This leads to the pattern to be introduced here in Part 3.&lt;/p&gt;

&lt;p&gt;First, all the example components we have worked through form a data structure called Binary Tree. Below is the graphic from the Vue documentation for nested components in the computer memory when a Vue app is running: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lAEDDBjV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oozxxgcurdbsi0aeua2n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lAEDDBjV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oozxxgcurdbsi0aeua2n.png" alt="Image description" width="880" height="340"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is another binary tree with more levels:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--L7ALm64a--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p20xytuqw975v4mk5fhu.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--L7ALm64a--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p20xytuqw975v4mk5fhu.jpg" alt="Image description" width="600" height="351"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now suppose we have these components below nested together:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;App&lt;/code&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Parent&lt;/code&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;ChildA&lt;/code&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;GrandchildA&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;


&lt;/blockquote&gt;
&lt;br&gt;
&lt;/blockquote&gt;
&lt;br&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xlXH_JZ7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7xeu4mc10cfy0hd655tx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xlXH_JZ7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7xeu4mc10cfy0hd655tx.png" alt="Image description" width="880" height="1037"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;App&lt;/code&gt;, we bind an event named &lt;code&gt;change:font&lt;/code&gt; onto &lt;code&gt;Parent&lt;/code&gt;, the callback function is &lt;code&gt;handleChangeFont&lt;/code&gt; which will update the font size for &lt;code&gt;Parent&lt;/code&gt; and its descendants, according to the argument size passed in.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Parent&lt;/code&gt; is the same as previous examples, it maintains a list of &lt;code&gt;desserts&lt;/code&gt; and passes it to &lt;code&gt;ChildA&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BU8TVX8V--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hdd2zsxog0vfm8vkyq29.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BU8TVX8V--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hdd2zsxog0vfm8vkyq29.png" alt="Image description" width="880" height="1609"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ChildA&lt;/code&gt; and &lt;code&gt;GrandchildA&lt;/code&gt; are simple, &lt;code&gt;ChildA&lt;/code&gt; receives the prop and passes it down to &lt;code&gt;GrandchildA&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--__q7WFJB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/el88mbjc4vjve0hswjmn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--__q7WFJB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/el88mbjc4vjve0hswjmn.png" alt="Image description" width="880" height="1186"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5EPS_jT9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/626uksm0o29l5z966fej.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5EPS_jT9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/626uksm0o29l5z966fej.png" alt="Image description" width="880" height="903"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And this is what the view looks like at the moment:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--T7wTSNg6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fbeqtn8h4rw9ufjm016h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--T7wTSNg6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fbeqtn8h4rw9ufjm016h.png" alt="Image description" width="880" height="1109"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now for some business requirements, users want to change the font size by clicking a button named &lt;code&gt;Change Font Size&lt;/code&gt; in &lt;code&gt;GrandchildA&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IROoCoFH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4hggpfbvlnyrt8qmtvgf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IROoCoFH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4hggpfbvlnyrt8qmtvgf.png" alt="Image description" width="880" height="1094"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can do so by utilizing the "$parent" pattern from &lt;a href="https://csdigitalnomad.medium.com/vue-js-components-communication-patterns-without-vuex-part-2-7f9c0bc132a2"&gt;Part 2&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Tb6XpOHz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n8snv7tlkxzlv684ngym.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Tb6XpOHz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n8snv7tlkxzlv684ngym.png" alt="Image description" width="880" height="1054"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Line 30 is the "$parent" pattern in action. Click on the button, the font size on the view becomes 20px:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GhAH_CPB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9n49ccqqyvkq4y14vm1j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GhAH_CPB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9n49ccqqyvkq4y14vm1j.png" alt="Image description" width="880" height="1100"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Awesome!&lt;/p&gt;

&lt;p&gt;But as you can see, with the complexity of the nesting, we would have to code something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;change:font&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;20px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;if users want to add that button in a grand-grand-grand-grandchild component.&lt;/p&gt;

&lt;p&gt;A better solution in a large tree structure would come in handy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Upward broadcast pattern
&lt;/h2&gt;

&lt;p&gt;If a component wants to inform an ancestor component via triggering one of its events, this component can literally "broadcast" upward to all its ancestors about an event it wants to trigger, and if one ancestor component has that specific event registered, it will perform the callback function automatically. We can implement this event mechanism on the &lt;code&gt;Vue&lt;/code&gt; prototype object, so all the &lt;code&gt;VueComponent&lt;/code&gt; instances can have access to it via &lt;code&gt;this&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;main.js&lt;/code&gt;, let's create a function named &lt;code&gt;$upwardBroadcast&lt;/code&gt; on &lt;code&gt;Vue.prototype&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Ca_YTt23--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/889gzb7xs91umb42cz42.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ca_YTt23--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/889gzb7xs91umb42cz42.png" alt="Image description" width="735" height="387"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;$upwardBroadcast&lt;/code&gt; function has two parameters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;event&lt;/code&gt;: the event being broadcast upward from the current component&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;args&lt;/code&gt;: the data being passed when emitting the event&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It will broadcast an event from the current component upward to all the ancestors, if one ancestor in the upward tree hierarchy has that event registered, it will respond and execute the callback function registered alone with the event. Let's implement it:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4FE7CUcI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/go1ra40u18ehxhfyal5p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4FE7CUcI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/go1ra40u18ehxhfyal5p.png" alt="Image description" width="734" height="253"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First, at line 12, we save the parent of the current component. In lines 12 - 16, if the parent exists, it will use the parent instance to emit the event, then proceed to the parent's parent, and the parent's parent's parent, etc.&lt;br&gt;
The &lt;code&gt;while&lt;/code&gt; loop stops when there is no parent anymore, meaning it has reached the top (root) node on the tree.&lt;/p&gt;

&lt;p&gt;Now let's see how to use it to improve the previous "$parent" pattern in &lt;code&gt;GrandchildA&lt;/code&gt;. Very simple, just one line of change:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--31yITqok--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/witatov5ey3f3ennyfum.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--31yITqok--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/witatov5ey3f3ennyfum.png" alt="Image description" width="561" height="760"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Line 31 replaces line 30 and uses the &lt;code&gt;$upwardBroadcast&lt;/code&gt; function via &lt;code&gt;this&lt;/code&gt;, and it broadcasts the event &lt;code&gt;change:font&lt;/code&gt; and passes the argument &lt;code&gt;'20px'&lt;/code&gt;. If we click the button, the font size changes as before:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yexjWWLF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yhv2i2tpcv359d250j25.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yexjWWLF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yhv2i2tpcv359d250j25.png" alt="Image description" width="880" height="1100"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Special Note
&lt;/h2&gt;

&lt;p&gt;Here I say "uses the &lt;code&gt;$upwardBroadcast&lt;/code&gt; function &lt;strong&gt;via&lt;/strong&gt; &lt;code&gt;this&lt;/code&gt;", not "&lt;strong&gt;on&lt;/strong&gt;" &lt;code&gt;this&lt;/code&gt;, because &lt;code&gt;$upwardBroadcast&lt;/code&gt; is not defined on the &lt;code&gt;VueComponent&lt;/code&gt; instance created from the &lt;code&gt;VueComponent&lt;/code&gt; constructor function, but on the &lt;code&gt;Vue&lt;/code&gt; constructor's prototype - as what we did in &lt;code&gt;main.js&lt;/code&gt;. Yes, a better understanding of Vue.js requires a solid foundation of JavaScript basics, that's why I like Vue so much - you are not just using a framework to do the work, but you get to consolidate and deepen basic knowledge of JavaScript.&lt;/p&gt;

&lt;p&gt;But if you think about it a bit - how come a &lt;code&gt;VueComponent&lt;/code&gt; instance can access the &lt;code&gt;Vue&lt;/code&gt; constructor's prototype?Actually, Vue did one thing on top of the JavaScript prototype chain - it modified where &lt;code&gt;VueComponent.prototype&lt;/code&gt; points.&lt;/p&gt;

&lt;p&gt;Also, the function name starts with a &lt;code&gt;$&lt;/code&gt; sign, and this is only because this is the convention of all the built-in properties and methods in Vue.js.&lt;/p&gt;

&lt;h2&gt;
  
  
  Downward broadcast pattern
&lt;/h2&gt;

&lt;p&gt;Now let's implement a downward broadcast mechanism. In &lt;code&gt;main.js&lt;/code&gt;, let's create another function named &lt;code&gt;$downwardBroadcast&lt;/code&gt; on &lt;code&gt;Vue.prototype&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--T5nGe01_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ci2imotaxxok8jv6woyb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--T5nGe01_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ci2imotaxxok8jv6woyb.png" alt="Image description" width="765" height="189"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It has the same two parameters as &lt;code&gt;$upwardBroadcast&lt;/code&gt;, and it will broadcast an event from the current component downward to all the descendants, if one descendant in the downward tree hierarchy has that event registered, it will respond and execute the callback function. We can do so:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IIX_RYZ7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/afe40ir7h049knmsn9ky.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IIX_RYZ7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/afe40ir7h049knmsn9ky.png" alt="Image description" width="759" height="292"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First, we get all the descendants of the current component, and for each child, it will emit the event. Here what is different from one child only having one parent in &lt;code&gt;$upwardBroadcast&lt;/code&gt;, is that now each child can have many children, so if there are any children components of a current child, we need to repeat the same logic, as seen in line 28.&lt;/p&gt;

&lt;p&gt;This is the perfect case for recursion, and let's implement it:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--b6yjTFLB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zu1nag2vx1fed7562vey.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--b6yjTFLB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zu1nag2vx1fed7562vey.png" alt="Image description" width="771" height="335"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the function body, we create another function called &lt;code&gt;downwardBroadcast&lt;/code&gt;. First, we execute this function by passing in the current component's &lt;code&gt;this.$children&lt;/code&gt; array, as seen in line 33. Then within &lt;code&gt;downwardBroadcast&lt;/code&gt;, we loop through the children array, and if there are children under the current child, we will execute &lt;code&gt;downwardBroadcast&lt;/code&gt; again, passing in the current child's &lt;code&gt;$children&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now our &lt;code&gt;main.js&lt;/code&gt; looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Tab_myvW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cuya8in2bp6pvir7vqbk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Tab_myvW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cuya8in2bp6pvir7vqbk.png" alt="Image description" width="746" height="821"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Time to see it in action. We will downward broadcast an event named &lt;code&gt;show:year&lt;/code&gt; in &lt;code&gt;App&lt;/code&gt; to all its descendants after clicking a new button named &lt;code&gt;Display current year&lt;/code&gt;, and the argument passed in is the current year:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bhrHdanu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pilgmyaudc2m546rcoka.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bhrHdanu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pilgmyaudc2m546rcoka.png" alt="Image description" width="644" height="865"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--x8vy5kNO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q2kgsvmbf5e8lobk2wfi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--x8vy5kNO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q2kgsvmbf5e8lobk2wfi.png" alt="Image description" width="590" height="722"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;ChildA&lt;/code&gt;, we bind this event onto &lt;code&gt;GrandchildA&lt;/code&gt;, the callback function is &lt;code&gt;ChildA.showYear()&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BXn5Psbl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sk6p1rdl4ehnnh5goyad.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BXn5Psbl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sk6p1rdl4ehnnh5goyad.png" alt="Image description" width="507" height="825"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on the button, the alert window is shown:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CQEOhxRk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hw3xlo48vd2mvl01kkwc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CQEOhxRk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hw3xlo48vd2mvl01kkwc.png" alt="Image description" width="599" height="733"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The broadcasting is powerful, isn't it?&lt;/p&gt;

&lt;h2&gt;
  
  
  Encapsulate the functions ( Hooks / Composition style)
&lt;/h2&gt;

&lt;p&gt;One thing we can improve is to move the functions in &lt;code&gt;main.js&lt;/code&gt; into a separate file - &lt;code&gt;src/hooks/events.js&lt;/code&gt;, &lt;br&gt;
so this file contains functions that enhance the event system on &lt;code&gt;Vue.prototype&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--b5JB4IKp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qlwav1hbelxbyhgzcopz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--b5JB4IKp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qlwav1hbelxbyhgzcopz.png" alt="Image description" width="757" height="1138"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Following the naming convention of Hooks or Composition API, we create two new functions named &lt;code&gt;useUpwardBroadcast&lt;/code&gt; and &lt;code&gt;useDownwardBroadcast&lt;/code&gt;, the parameter is the &lt;code&gt;Vue&lt;/code&gt; constructor function. Within each function body, it is the previous function defined.&lt;/p&gt;

&lt;p&gt;Now in &lt;code&gt;main.js&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WMe6seG4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bqqdxp0g9mc4cbpgbcem.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WMe6seG4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bqqdxp0g9mc4cbpgbcem.png" alt="Image description" width="626" height="296"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;we can import these two functions and run them to enhance &lt;code&gt;Vue.prototype&lt;/code&gt;, if we need.&lt;/p&gt;

&lt;p&gt;In the next part of this series, we will explore another mighty Vue.js components pattern.&lt;/p&gt;

&lt;p&gt;Here are all the articles in this series:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;&lt;a href="https://csdigitalnomad.medium.com/vue-js-components-communication-patterns-without-vuex-part-1-e9da6a0285ac"&gt;Vue.js Components Communication Patterns (without Vuex) - Part 1&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;&lt;a href="https://csdigitalnomad.medium.com/vue-js-components-communication-patterns-without-vuex-part-2-7f9c0bc132a2"&gt;Vue.js Components Communication Patterns (without Vuex) - Part 2&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;&lt;a href="https://csdigitalnomad.medium.com/vue-js-components-communication-patterns-without-vuex-part-3-5ccfdbe3ecfa"&gt;Vue.js Components Communication Patterns (without Vuex) - Part 3&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;&lt;a href="https://csdigitalnomad.medium.com/vue-js-components-communication-patterns-without-vuex-part-4-f99a17bd98f0"&gt;Vue.js Components Communication Patterns (without Vuex) - Part 4&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;&lt;a href="https://csdigitalnomad.medium.com/vue-js-components-communication-patterns-without-vuex-part-5-2cf6fb1c5e26"&gt;Vue.js Components Communication Patterns (without Vuex) - Part 5&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;&lt;a href="https://csdigitalnomad.medium.com/vue-js-components-communication-patterns-without-vuex-part-6-10e4e43f0ac7"&gt;Vue.js Components Communication Patterns (without Vuex) - Part 6&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;&lt;a href="https://csdigitalnomad.medium.com/vue-js-components-communication-patterns-without-vuex-part-7-15c5b786539e"&gt;Vue.js Components Communication Patterns (without Vuex) - Part 7&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>vue</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Build your own Vue.js UI library based on Vuetify and publish it to NPM</title>
      <dc:creator>Chris Y.</dc:creator>
      <pubDate>Tue, 23 Nov 2021 00:21:35 +0000</pubDate>
      <link>https://dev.to/chris_y/build-your-own-vuejs-ui-library-based-on-vuetify-and-publish-it-to-npm-5dng</link>
      <guid>https://dev.to/chris_y/build-your-own-vuejs-ui-library-based-on-vuetify-and-publish-it-to-npm-5dng</guid>
      <description>&lt;p&gt;&lt;strong&gt;&lt;em&gt;Customize and enhance Vuetify components&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Vue.js is a simple yet powerful front-end JavaScript framework that is designed exquisitely. In my opinion, Vue.js is the first choice for the UI of middle to large-sized projects. Over the years, there are a wide range of UI component libraries for Vue.js, and the most popular one seems to have been &lt;a href="https://vuetifyjs.com/"&gt;Vuetify&lt;/a&gt;. Often based on our own business and project requirements, we need to customize an open-source UI library component, and this article shows how to build our custom UI components based on Vuetify.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a Vue + Vuetify project
&lt;/h2&gt;

&lt;p&gt;First Let’s create a new Vue.js project with Vuetify. Following the &lt;a href="https://vuetifyjs.com/en/getting-started/installation/#vue-cli-install"&gt;Vuetify guide&lt;/a&gt;, it is very easy:&lt;/p&gt;

&lt;p&gt;We first create a new project named &lt;code&gt;custom-ui&lt;/code&gt; using &lt;code&gt;Vue CLI&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vue create custom-ui
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then in the project root, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vue add vuetify
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And it’s all ready to go. After cleaning up &lt;code&gt;App.vue&lt;/code&gt; and delete &lt;code&gt;HelloWorld.vue&lt;/code&gt;, our project structure looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hTLqNbz---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7mxs0ofg2pp5r2nutea8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hTLqNbz---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7mxs0ofg2pp5r2nutea8.png" alt="Image description" width="700" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It currently just renders a blank page.&lt;/p&gt;

&lt;p&gt;Now let’s use a Vuetify button component &lt;code&gt;&amp;lt;v-btn&amp;gt;&lt;/code&gt; and see how it works:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vaiAg02N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cc45vwcs5rvx29gt2x1p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vaiAg02N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cc45vwcs5rvx29gt2x1p.png" alt="Image description" width="700" height="838"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here we used:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a prop named &lt;code&gt;color&lt;/code&gt; to specify a primary material design color (by default it is grey color),&lt;/li&gt;
&lt;li&gt;a prop named &lt;code&gt;rounded&lt;/code&gt; to make the button have rounded edges (by default it is not rounded),&lt;/li&gt;
&lt;li&gt;an event listener for the &lt;code&gt;click&lt;/code&gt; event,&lt;/li&gt;
&lt;li&gt;an event listener for the &lt;code&gt;mouseover&lt;/code&gt; event,&lt;/li&gt;
&lt;li&gt;the text "Custom Button" for the button.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once clicking the button or mousing over it, the event handler functions are triggered and the text is output in the console:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fC9XY-ms--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6nxq5o4gi5kmpfux36th.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fC9XY-ms--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6nxq5o4gi5kmpfux36th.png" alt="Image description" width="700" height="679"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It works as expected.&lt;/p&gt;

&lt;p&gt;Suppose now we need to use this button (with primary color, rounded edges, default text, and two mouse events) in multiple places in our project and later in other projects as well, instead of copying and pasting code, ideally it is better to encapsulate what we have done into a new component. Later we can publish our custom UI library onto npm, and whichever project needs to use them can just &lt;code&gt;npm install&lt;/code&gt; the package.&lt;/p&gt;

&lt;p&gt;Let’s go ahead and create this custom component first.&lt;/p&gt;

&lt;p&gt;We will create a new directory named &lt;code&gt;MyLib&lt;/code&gt;, and within it, we create an &lt;code&gt;index.js&lt;/code&gt; file and a &lt;code&gt;MyButton&lt;/code&gt; component:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--73RZiAwx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lyzkn9pq2lmoq0z94gs2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--73RZiAwx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lyzkn9pq2lmoq0z94gs2.png" alt="Image description" width="700" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Like many open-source libraries, the purpose of the &lt;code&gt;index.js&lt;/code&gt; file is to import all the components and export them out in one big object.&lt;/p&gt;

&lt;p&gt;We move the &lt;code&gt;&amp;lt;v-btn&amp;gt;&lt;/code&gt; from &lt;code&gt;App&lt;/code&gt; to &lt;code&gt;MyButton&lt;/code&gt;, and import &lt;code&gt;MyButton&lt;/code&gt; from &lt;code&gt;MyLib&lt;/code&gt;, the project now looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MQrCjQZv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6e6ytti5eocbmbct8p7z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MQrCjQZv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6e6ytti5eocbmbct8p7z.png" alt="Image description" width="700" height="678"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The two event handler functions are still in the parent &lt;code&gt;App&lt;/code&gt; component, and the events are bound on the child component &lt;code&gt;MyButton&lt;/code&gt;, which is the common practice in a component-based framework. Within &lt;code&gt;MyButton&lt;/code&gt;, we still have the "default" value for color, rounded, and button text. For a component, we want it to be able to accept props passed from the parent, and props can have the default values that we want, so let’s add three props for &lt;code&gt;MyButton&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lAvqiOOR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t5tsgih4vaugzbdx4pww.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lAvqiOOR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t5tsgih4vaugzbdx4pww.png" alt="Image description" width="520" height="746"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The props &lt;code&gt;color&lt;/code&gt; and &lt;code&gt;rounded&lt;/code&gt; are bound onto the &lt;code&gt;&amp;lt;v-btn&amp;gt;&lt;/code&gt;’s color and rounded, and &lt;code&gt;text&lt;/code&gt; is placed in a &lt;code&gt;slot&lt;/code&gt;. Refresh the page, the button still looks the same as before with the default values.&lt;/p&gt;

&lt;p&gt;Now we can pass different values for these three props in the parent App component as well:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ck40AmVA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/54sv0g2pndqqph8oj0yl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ck40AmVA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/54sv0g2pndqqph8oj0yl.png" alt="Image description" width="700" height="767"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--o9gbr7r_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rovtfc1nn3umb3x3ok9i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--o9gbr7r_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rovtfc1nn3umb3x3ok9i.png" alt="Image description" width="700" height="581"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The color, edges, and text of the button are all changed. For the text, you can also pass a slot to &lt;code&gt;MyButton&lt;/code&gt;, and it will override the default one.&lt;/p&gt;

&lt;p&gt;If you take a look at &lt;code&gt;&amp;lt;v-btn&amp;gt;&lt;/code&gt;'s &lt;a href="https://vuetifyjs.com/en/api/v-btn/"&gt;API document&lt;/a&gt;, it has many other props. Let’s try some on &lt;code&gt;MyButton&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--N_N73TQU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8kqrbnhaf7jnbvfktp62.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--N_N73TQU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8kqrbnhaf7jnbvfktp62.png" alt="Image description" width="486" height="909"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We add &lt;code&gt;outlined&lt;/code&gt; onto our &lt;code&gt;MyButton&lt;/code&gt; component according to &lt;code&gt;&amp;lt;v-btn&amp;gt;&lt;/code&gt; API. If you refresh the page, the button actually does not become the outlined style. It is not working, why? Because our own component works like a &lt;em&gt;wrapper component&lt;/em&gt; for &lt;code&gt;&amp;lt;v-btn&amp;gt;&lt;/code&gt; — we can customize some styling, add some default values, etc., which is similar to a concept popular in React.js — &lt;em&gt;Higher Order Component&lt;/em&gt;. What we can do now is to use a powerful feature in Vue.js —&lt;code&gt;$attrs&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  $attrs
&lt;/h2&gt;

&lt;p&gt;The document briefs &lt;code&gt;$attrs&lt;/code&gt; as below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yzD_K3Uo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lpn7y8umthqn4xrdmyt8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yzD_K3Uo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lpn7y8umthqn4xrdmyt8.png" alt="Image description" width="700" height="342"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Basically what it means is, in a parent component such as &lt;code&gt;App&lt;/code&gt;, when we bind some attributes onto a child component such as &lt;code&gt;MyButton&lt;/code&gt;, if these attributes are not declared in the child component as &lt;code&gt;props&lt;/code&gt;, then Vue.js will add those attributes onto the root element of the child component. &lt;br&gt;
Let’s see it in action.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;App&lt;/code&gt;, we have already bound a new attribute &lt;code&gt;outlined&lt;/code&gt; on &lt;code&gt;MyButton&lt;/code&gt;, now in &lt;code&gt;MyButton&lt;/code&gt;, we will add &lt;code&gt;v-bind="$attrs"&lt;/code&gt; onto the &lt;code&gt;&amp;lt;v-btn&amp;gt;&lt;/code&gt; in &lt;code&gt;MyButton&lt;/code&gt; component:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RBN0E0cL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7eurvwr129lt5iywpjjp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RBN0E0cL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7eurvwr129lt5iywpjjp.png" alt="Image description" width="700" height="778"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Refresh the page, and it works:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mKtaMjCN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ux7np8b2a5dhx8vjyiaw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mKtaMjCN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ux7np8b2a5dhx8vjyiaw.png" alt="Image description" width="700" height="603"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What happened is, because of &lt;code&gt;v-bind="$attrs"&lt;/code&gt;, now any non-declared attributes passed from &lt;code&gt;App&lt;/code&gt; to &lt;code&gt;MyButton&lt;/code&gt; (such as &lt;code&gt;outlined&lt;/code&gt;) are added onto the root element of &lt;code&gt;MyButton&lt;/code&gt;, which is &lt;code&gt;&amp;lt;v-btn&amp;gt;&lt;/code&gt;, and &lt;code&gt;outlined&lt;/code&gt; is a &lt;code&gt;prop&lt;/code&gt; defined in &lt;code&gt;&amp;lt;v-btn&amp;gt;&lt;/code&gt;, so it works on it and the outlined button is rendered.&lt;/p&gt;

&lt;p&gt;In a nutshell:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;$attrs&lt;/code&gt; is an object on a &lt;code&gt;VueComponent&lt;/code&gt; instance that collects all the &lt;strong&gt;non-declared attributes&lt;/strong&gt; bound onto this component.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In the &lt;code&gt;$attrs&lt;/code&gt; object, the key name is the attribute name, they value is the attribute value.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Correspondingly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;$props&lt;/code&gt; is an object on a &lt;code&gt;VueComponent&lt;/code&gt; instance that collects all the &lt;strong&gt;declared properties&lt;/strong&gt; bound onto this component.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UVFz-zGW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gg77wl4cs2kigw5rwarb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UVFz-zGW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gg77wl4cs2kigw5rwarb.png" alt="Image description" width="700" height="251"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s output &lt;code&gt;$attrs&lt;/code&gt; and &lt;code&gt;$props&lt;/code&gt; in &lt;code&gt;MyButton&lt;/code&gt; to see them more clearly:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iztsEvwH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1g54gr2p3154w2ggmc4m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iztsEvwH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1g54gr2p3154w2ggmc4m.png" alt="Image description" width="700" height="908"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Both &lt;code&gt;$attrs&lt;/code&gt; and &lt;code&gt;$props&lt;/code&gt; are important properties on the &lt;code&gt;VueComponent&lt;/code&gt; instance. Also, you can iterate &lt;code&gt;$attrs&lt;/code&gt; or extract certain attributes out, depending on your needs. If you want to apply &lt;code&gt;v-bind="$attrs"&lt;/code&gt; onto other elements in the &lt;code&gt;&amp;lt;template&amp;gt;&lt;/code&gt; instead of the root one, you can set the &lt;code&gt;inheritAttrs&lt;/code&gt; option to &lt;code&gt;false&lt;/code&gt; in the component’s &lt;code&gt;configs&lt;/code&gt; object. Please refer to the document about &lt;a href="https://vuejs.org/v2/api/#inheritAttrs"&gt;&lt;code&gt;inheritAttrs&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aSiB3F4Z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/as85uge0hjg1dzc6mg9t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aSiB3F4Z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/as85uge0hjg1dzc6mg9t.png" alt="Image description" width="700" height="427"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So far we can apply all &lt;code&gt;&amp;lt;v-btn&amp;gt;&lt;/code&gt;'s props on our &lt;code&gt;MyButton&lt;/code&gt;, which is nice thanks to &lt;code&gt;$attrs&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Let’s take a look at the two event listeners now. If you click on or mouse over the button, the two event handler functions currently are not triggered. &lt;br&gt;
Similarly, there is another mighty &lt;code&gt;VueComponent&lt;/code&gt; instance property called &lt;code&gt;$listeners&lt;/code&gt; that can help.&lt;/p&gt;

&lt;h2&gt;
  
  
  $listeners
&lt;/h2&gt;

&lt;p&gt;According to the document:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--S395pZ_N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xwsc6udgzlzejeoh0j3k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--S395pZ_N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xwsc6udgzlzejeoh0j3k.png" alt="Image description" width="700" height="311"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What it means is, in the parent component &lt;code&gt;App&lt;/code&gt;, all the events (DOM native or custom) bound onto the child component &lt;code&gt;MyButton&lt;/code&gt; will be collected into&lt;br&gt;
the child component’s &lt;code&gt;$listeners&lt;/code&gt; object. Let’s output it in the console to take a look:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lXiQloIt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gtqbdfzp77jalgg21a0j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lXiQloIt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gtqbdfzp77jalgg21a0j.png" alt="Image description" width="700" height="652"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ockBhba4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hjmkfz3e62uk40ej330i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ockBhba4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hjmkfz3e62uk40ej330i.png" alt="Image description" width="700" height="964"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;$listeners&lt;/code&gt; object contains the two events &lt;code&gt;click&lt;/code&gt; and &lt;code&gt;mouseover&lt;/code&gt; that the parent &lt;code&gt;App&lt;/code&gt; bound onto it. &lt;br&gt;
Now we can add a new line of code &lt;code&gt;v-on="$listeners"&lt;/code&gt; on &lt;code&gt;&amp;lt;v-btn&amp;gt;&lt;/code&gt; in &lt;code&gt;MyButton&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Zr77z3Cp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eiwtqgru3g38gosm4ku8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Zr77z3Cp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eiwtqgru3g38gosm4ku8.png" alt="Image description" width="560" height="892"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Refresh the page and click on the button again:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yLmZYFjH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v6xezhwkiyn79rmx87mg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yLmZYFjH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v6xezhwkiyn79rmx87mg.png" alt="Image description" width="700" height="773"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The event callback functions are working now, awesome.&lt;/p&gt;

&lt;p&gt;In a nutshell:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;$listeners&lt;/code&gt; is an object on a &lt;code&gt;VueComponent&lt;/code&gt; instance that collects all the &lt;strong&gt;events + event handler functions&lt;/strong&gt; bound onto this component.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Like &lt;code&gt;$attrs&lt;/code&gt;, a component can pass its &lt;code&gt;$listeners&lt;/code&gt; to a descendant component.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In &lt;code&gt;MyButton&lt;/code&gt;, by adding &lt;code&gt;v-on="$listeners"&lt;/code&gt; on its child component &lt;code&gt;&amp;lt;v-btn&amp;gt;&lt;/code&gt;, it passes its &lt;code&gt;$listeners&lt;/code&gt; to &lt;code&gt;&amp;lt;v-btn&amp;gt;&lt;/code&gt;, &lt;br&gt;
and when the event (the &lt;code&gt;key&lt;/code&gt; filed in the &lt;code&gt;$listeners&lt;/code&gt; object) is triggered, the corresponding callback function defined in the parent will be executed.&lt;/p&gt;

&lt;p&gt;Except for &lt;code&gt;v-on="$listeners"&lt;/code&gt;, you can also execute an event callback function directly in the child component using &lt;code&gt;this.$listeners.eventname()&lt;/code&gt;, or you can destructure the &lt;code&gt;$listeners&lt;/code&gt; object and even add new &lt;code&gt;key:value&lt;/code&gt; pair into it to suit your specific needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Publish to NPM
&lt;/h2&gt;

&lt;p&gt;Now our &lt;code&gt;MyButton&lt;/code&gt; component is ready to go. We can &lt;code&gt;import&lt;/code&gt; it into other places in the project, or we can enter the &lt;code&gt;MyLib&lt;/code&gt; directory, run &lt;code&gt;npm init&lt;/code&gt; to generate a &lt;code&gt;package.json&lt;/code&gt; file, add the necessary metadata for our custom &lt;code&gt;MyLib&lt;/code&gt; UI library, and run &lt;code&gt;npm publish&lt;/code&gt; to push it onto &lt;code&gt;npm&lt;/code&gt;. Other projects just need to install the &lt;code&gt;MyLib&lt;/code&gt; package and can use &lt;code&gt;MyButton&lt;/code&gt; and other custom components.&lt;/p&gt;

&lt;p&gt;For more articles about &lt;code&gt;$attrs&lt;/code&gt; and &lt;code&gt;$listeners&lt;/code&gt;, please check out:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;&lt;a href="https://csdigitalnomad.medium.com/vue-js-components-communication-patterns-without-vuex-part-4-f99a17bd98f0"&gt;Vue.js Components Communication Patterns (without Vuex) - Part 4&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;&lt;a href="https://csdigitalnomad.medium.com/vue-js-components-communication-patterns-without-vuex-part-5-2cf6fb1c5e26"&gt;Vue.js Components Communication Patterns (without Vuex) - Part 5&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Vue.js Components Communication Patterns (without Vuex) - Part 2</title>
      <dc:creator>Chris Y.</dc:creator>
      <pubDate>Mon, 22 Nov 2021 22:49:03 +0000</pubDate>
      <link>https://dev.to/chris_y/vuejs-components-communication-patterns-without-vuex-part-2-1l00</link>
      <guid>https://dev.to/chris_y/vuejs-components-communication-patterns-without-vuex-part-2-1l00</guid>
      <description>&lt;p&gt;&lt;strong&gt;&lt;em&gt;$parent and $children patterns&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In &lt;a href="https://csdigitalnomad.medium.com/vue-js-components-communication-patterns-without-vuex-part-1-e9da6a0285ac"&gt;Part 1&lt;/a&gt; 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? &lt;br&gt;
Now following the starting examples of &lt;a href="https://csdigitalnomad.medium.com/vue-js-components-communication-patterns-without-vuex-part-1-e9da6a0285ac"&gt;Part 1&lt;/a&gt;, &lt;br&gt;
let's add a new component &lt;code&gt;GrandchildA&lt;/code&gt;, and here is the initial state of the three components:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tIqAzymY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xv581p9awf4vnlo3lza0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tIqAzymY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xv581p9awf4vnlo3lza0.png" alt="Image description" width="549" height="995"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Parent&lt;/code&gt; has a &lt;code&gt;ChildA&lt;/code&gt; component that gets an &lt;code&gt;input&lt;/code&gt; event bound onto its tag. This is the "custom v-model" pattern discussed in &lt;a href="https://csdigitalnomad.medium.com/vue-js-components-communication-patterns-without-vuex-part-1-e9da6a0285ac"&gt;Part 1&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fsMgS_It--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i3pzcne8n9c0omj305k0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fsMgS_It--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i3pzcne8n9c0omj305k0.png" alt="Image description" width="588" height="1071"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;Also, &lt;code&gt;GrandchildA&lt;/code&gt; will pass its data to &lt;code&gt;ChildA&lt;/code&gt;, and &lt;code&gt;ChildA&lt;/code&gt; will pass it back to &lt;code&gt;Parent&lt;/code&gt;, as seen in lines 43 - 46.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xYf-BWx7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xgjp1i72c55yiaynbl1p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xYf-BWx7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xgjp1i72c55yiaynbl1p.png" alt="Image description" width="530" height="909"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;GrandchildA&lt;/code&gt; has the same settings as &lt;code&gt;ChildA&lt;/code&gt; in &lt;a href="https://csdigitalnomad.medium.com/vue-js-components-communication-patterns-without-vuex-part-1-e9da6a0285ac"&gt;Part 1&lt;/a&gt;, it has a button where we can add a new dessert. &lt;br&gt;
In the event handler function &lt;code&gt;handleUpdate&lt;/code&gt;, it will use &lt;code&gt;$emit&lt;/code&gt; to trigger the &lt;code&gt;input&lt;/code&gt; event bound onto it in &lt;code&gt;ChildA&lt;/code&gt;, and pass the new data as the argument.&lt;/p&gt;

&lt;p&gt;Here is the current view:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gm2_DN5t--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lph4y2mhraoezxhu1f69.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gm2_DN5t--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lph4y2mhraoezxhu1f69.png" alt="Image description" width="574" height="654"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now if the user clicks the &lt;code&gt;Update&lt;/code&gt; button on &lt;code&gt;GrandchildA&lt;/code&gt;, the view becomes:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8SykMlWe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yzi52san9p9odz1isze1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8SykMlWe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yzi52san9p9odz1isze1.png" alt="Image description" width="571" height="652"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;So in order for &lt;code&gt;GrandchildA&lt;/code&gt; to communicate with &lt;code&gt;Parent&lt;/code&gt;, it must go through the middle man &lt;code&gt;ChildA&lt;/code&gt;. How about now we add a &lt;code&gt;GrandGrandchild&lt;/code&gt; component? It will follow the same approach, and both &lt;code&gt;ChildA&lt;/code&gt; and &lt;code&gt;GrandchildA&lt;/code&gt; will become the middle man. When it comes to a multi-level hierarchy, we can repeat the two patterns from &lt;a href="https://csdigitalnomad.medium.com/vue-js-components-communication-patterns-without-vuex-part-1-e9da6a0285ac"&gt;Part 1&lt;/a&gt; in each descendant component, but there is a better way.&lt;/p&gt;
&lt;h2&gt;
  
  
  $parent pattern
&lt;/h2&gt;

&lt;p&gt;Now let's modify &lt;code&gt;GrandchildA.handleUpdate()&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LF5DTRJ4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y480kaaqvt4z5okxggmb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LF5DTRJ4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y480kaaqvt4z5okxggmb.png" alt="Image description" width="502" height="931"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;Since we don't need &lt;code&gt;ChildA&lt;/code&gt; to do the middle man work anymore, now &lt;code&gt;ChildA&lt;/code&gt; can be very simple:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4L6rKPy4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wyhv4yydgsnji9999xfx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4L6rKPy4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wyhv4yydgsnji9999xfx.png" alt="Image description" width="502" height="1144"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ChildA&lt;/code&gt; becomes to only receive a prop and pass it to &lt;code&gt;GrandchildA&lt;/code&gt;. If we click the &lt;code&gt;Update&lt;/code&gt; button now, it works the same:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--x050Efqd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y9aelg8s5dpa8uffkqay.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--x050Efqd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y9aelg8s5dpa8uffkqay.png" alt="Image description" width="571" height="652"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The new &lt;code&gt;desserts&lt;/code&gt; data is updated from &lt;code&gt;GrandchildA&lt;/code&gt; directly to &lt;code&gt;Parent&lt;/code&gt;, then passed down to &lt;code&gt;ChildA&lt;/code&gt; and &lt;code&gt;GrandchildA&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  $children pattern
&lt;/h2&gt;

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

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7KJWXAey--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fflofqwvp5nsr54eev41.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7KJWXAey--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fflofqwvp5nsr54eev41.png" alt="Image description" width="495" height="822"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And the event callback function is &lt;code&gt;handleShowAlert&lt;/code&gt; which will show an alert. Now in &lt;code&gt;Parent&lt;/code&gt;, let's add a new button:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4wG5m53F--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aiq00x3eigpt44yow7dr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4wG5m53F--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aiq00x3eigpt44yow7dr.png" alt="Image description" width="568" height="1206"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When clicking the button, we want to trigger the &lt;code&gt;show:alert&lt;/code&gt; event on &lt;code&gt;GrandchildA&lt;/code&gt;, which will, in turn, execute &lt;code&gt;ChildA.handleShowAlert()&lt;/code&gt; to show the alert. This is achieved using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$children&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;$children&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;$emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;show:alert&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--r6HssmWo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ub1s2jkxgv43xz67vtcm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--r6HssmWo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ub1s2jkxgv43xz67vtcm.png" alt="Image description" width="590" height="650"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;An alert is shown as expected.&lt;/p&gt;
&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;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:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;input&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;desserts&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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 &lt;code&gt;$children&lt;/code&gt; array? This question will lead us to &lt;a href="https://csdigitalnomad.medium.com/vue-js-components-communication-patterns-without-vuex-part-3-5ccfdbe3ecfa"&gt;Part 3&lt;/a&gt; of this series where we will look to solve it.&lt;/p&gt;

&lt;p&gt;Here are all the articles in this series:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;&lt;a href="https://csdigitalnomad.medium.com/vue-js-components-communication-patterns-without-vuex-part-1-e9da6a0285ac"&gt;Vue.js Components Communication Patterns (without Vuex) - Part 1&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;&lt;a href="https://csdigitalnomad.medium.com/vue-js-components-communication-patterns-without-vuex-part-2-7f9c0bc132a2"&gt;Vue.js Components Communication Patterns (without Vuex) - Part 2&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;&lt;a href="https://csdigitalnomad.medium.com/vue-js-components-communication-patterns-without-vuex-part-3-5ccfdbe3ecfa"&gt;Vue.js Components Communication Patterns (without Vuex) - Part 3&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;&lt;a href="https://csdigitalnomad.medium.com/vue-js-components-communication-patterns-without-vuex-part-4-f99a17bd98f0"&gt;Vue.js Components Communication Patterns (without Vuex) - Part 4&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;&lt;a href="https://csdigitalnomad.medium.com/vue-js-components-communication-patterns-without-vuex-part-5-2cf6fb1c5e26"&gt;Vue.js Components Communication Patterns (without Vuex) - Part 5&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;&lt;a href="https://csdigitalnomad.medium.com/vue-js-components-communication-patterns-without-vuex-part-6-10e4e43f0ac7"&gt;Vue.js Components Communication Patterns (without Vuex) - Part 6&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;&lt;a href="https://csdigitalnomad.medium.com/vue-js-components-communication-patterns-without-vuex-part-7-15c5b786539e"&gt;Vue.js Components Communication Patterns (without Vuex) - Part 7&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>vue</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Vue.js Components Communication Patterns (without Vuex) - Part 1</title>
      <dc:creator>Chris Y.</dc:creator>
      <pubDate>Mon, 22 Nov 2021 22:34:05 +0000</pubDate>
      <link>https://dev.to/chris_y/vuejs-components-communication-patterns-without-vuex-part-1-3pkj</link>
      <guid>https://dev.to/chris_y/vuejs-components-communication-patterns-without-vuex-part-1-3pkj</guid>
      <description>&lt;p&gt;&lt;strong&gt;&lt;em&gt;Custom v-model and .sync patterns&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  About this series
&lt;/h2&gt;

&lt;p&gt;Communication between components is one of the core parts of frontend frameworks. First, same as React, Vue's data flow is also one-way. You might have come across "two-way data flow using v-model" in some tutorials, but that is not accurate. Data flow in Vue is unidirectional. Vuex is great for sharing data between components, but when it comes to some scenarios such as &lt;strong&gt;building a UI library or a state management library&lt;/strong&gt;, Vuex is not suitable anymore, and we need to utilize the build-in mechanism of Vue itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Custom v-model pattern
&lt;/h2&gt;

&lt;p&gt;Here we have two components - &lt;code&gt;Parent&lt;/code&gt; and &lt;code&gt;ChildA&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Febqi9w3tfkvxl5m4g7p5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Febqi9w3tfkvxl5m4g7p5.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Parent&lt;/code&gt; displays a list of desserts which is an object array defined in the &lt;code&gt;data&lt;/code&gt; option, and also passes it to &lt;code&gt;ChildA&lt;/code&gt;'s prop &lt;code&gt;value&lt;/code&gt;. It also binds an event named &lt;code&gt;input&lt;/code&gt; onto the &lt;code&gt;ChildA&lt;/code&gt; instance, with the callback function being its &lt;code&gt;parentUpdate&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;Now let's look at &lt;code&gt;ChildA&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkdvb1zasdsnrrve5o4k3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkdvb1zasdsnrrve5o4k3.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ChildA&lt;/code&gt; also has a reactive data field named &lt;code&gt;desserts&lt;/code&gt; and its value is from the prop &lt;code&gt;value&lt;/code&gt; that &lt;code&gt;Parent&lt;/code&gt; passes in. At line 29, notice the spread operator - because of reference type, we need to make a copy of the data passed in by props. Otherwise, line 34 will modify the prop array directly, which will break Vue's one-way data flow.&lt;/p&gt;

&lt;p&gt;This is how the page looks at the moment:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8t9grvg41wm1h5v5ccho.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8t9grvg41wm1h5v5ccho.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When the button is clicked, &lt;code&gt;ChildA&lt;/code&gt; will emit the &lt;code&gt;input&lt;/code&gt; event bound onto it by &lt;code&gt;Parent&lt;/code&gt;, and the argument passed to&lt;br&gt;
&lt;code&gt;Parent.parentUpdate()&lt;/code&gt; is &lt;code&gt;ChildA.desserts&lt;/code&gt;. At line 47 in &lt;code&gt;Parent.parentUpdate()&lt;/code&gt;, &lt;code&gt;Parent&lt;/code&gt; updates its &lt;code&gt;desserts&lt;/code&gt; using the value passed from &lt;code&gt;ChildA&lt;/code&gt;. Now the view:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhir5qbqginb1f1103f9z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhir5qbqginb1f1103f9z.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This pattern can make sure some data in &lt;code&gt;Parent&lt;/code&gt; and &lt;code&gt;ChildA&lt;/code&gt; is "in sync". Data still flows one-way as we can clearly see above. &lt;/p&gt;

&lt;p&gt;We can also make the code a bit more concise by writing the function inline:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxlwq00ku1y5a4tr0spga.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxlwq00ku1y5a4tr0spga.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;because the logic here is just an assignment statement, we don't really need to define a method, and it works as before. Also, because this type of code is very common in application development, Vue has a shortcut syntax for it: &lt;code&gt;v-model&lt;/code&gt;. If we replace the &lt;code&gt;&amp;lt;ChildA&amp;gt;&lt;/code&gt; tag in &lt;code&gt;Parent&lt;/code&gt; with this one:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5vfdtp60pxv79hz86sv8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5vfdtp60pxv79hz86sv8.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We get the exact same result.&lt;/p&gt;

&lt;p&gt;In addition, you can change the prop and event name using the &lt;code&gt;model&lt;/code&gt; option &lt;a href="https://vuejs.org/v2/api/#model" rel="noopener noreferrer"&gt;https://vuejs.org/v2/api/#model&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  .sync pattern
&lt;/h2&gt;

&lt;p&gt;Since the event name is just a string registered in the event system as a key, how about in &lt;code&gt;Parent&lt;/code&gt; we change the event name bound onto &lt;code&gt;ChildA&lt;/code&gt; from &lt;code&gt;input&lt;/code&gt; to the string &lt;code&gt;update:value&lt;/code&gt;, to be more meaningful. Let's go back to the example before using &lt;code&gt;v-model&lt;/code&gt; and update the event name:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhc13i4u9xyfxbpdo79hg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhc13i4u9xyfxbpdo79hg.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As the event name is changed, in &lt;code&gt;ChildA&lt;/code&gt; now it needs to emit the new event name to trigger the event:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fszzt1y2i4mn4iss1g0ph.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fszzt1y2i4mn4iss1g0ph.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Run the code, and it works exactly the same as before. And similar to &lt;code&gt;v-model&lt;/code&gt;, Vue has another syntax shortcut for it which is &lt;code&gt;v-bind:value.sync&lt;/code&gt;. If we update &lt;code&gt;Parent&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8f2hia91cq5nid9xtsjk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8f2hia91cq5nid9xtsjk.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The result is the same.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's under the hood
&lt;/h2&gt;

&lt;p&gt;When Vue uses its &lt;code&gt;compileToFunctions&lt;/code&gt; function to compile the &lt;code&gt;&amp;lt;template&amp;gt;&lt;/code&gt; of a component:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;for any &lt;code&gt;v-model&lt;/code&gt; in the &lt;code&gt;&amp;lt;template&amp;gt;&lt;/code&gt;, it will generate &lt;code&gt;v-bind:value="xxx"&lt;/code&gt; and &lt;code&gt;v-on:input="val =&amp;gt; this.xxx = val"&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;for any &lt;code&gt;v-bind:value.sync="xxx"&lt;/code&gt; in the &lt;code&gt;&amp;lt;template&amp;gt;&lt;/code&gt;, it will generate &lt;code&gt;v-bind:value="xxx"&lt;/code&gt; and &lt;code&gt;v-on:update:value="val =&amp;gt; this.xxx = val"&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;for any event bound onto a child component tag:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Child&lt;/span&gt;
      &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;anyEvent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;parentUpdate&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;it will generate an object like so: &lt;code&gt;{anyEvent: parentUpdate}&lt;/code&gt;, and this object will be passed onto the Child component instance (of &lt;code&gt;VueComponent&lt;/code&gt; type). When the Child component gets this object, it will mount it onto itself via &lt;code&gt;this.$on('anyEvent', parentUpdate)&lt;/code&gt;. This way, the Child component can trigger its &lt;code&gt;anyEvent&lt;/code&gt; event via &lt;code&gt;this.emit('anyEvent', args)&lt;/code&gt; ( an event name is just a key registered in Vue's event system), and the callback function registered (a method on the Parent component) will be executed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The custom v-mode pattern and the .sync pattern work well in many cases, but what if we have a grandchild component and a grand grandchild component? Of course, we can repeat these two patterns in each descendant component, but will it start to become a bit clumsy? And this is what the &lt;a href="https://csdigitalnomad.medium.com/vue-js-components-communication-patterns-without-vuex-part-2-7f9c0bc132a2" rel="noopener noreferrer"&gt;Part 2&lt;/a&gt; of this series is about.&lt;/p&gt;

&lt;p&gt;Also check out the rest articles in this Vue.js components patterns series:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;&lt;a href="https://csdigitalnomad.medium.com/vue-js-components-communication-patterns-without-vuex-part-2-7f9c0bc132a2" rel="noopener noreferrer"&gt;Vue.js Components Communication Patterns (without Vuex) - Part 2&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;&lt;a href="https://csdigitalnomad.medium.com/vue-js-components-communication-patterns-without-vuex-part-3-5ccfdbe3ecfa" rel="noopener noreferrer"&gt;Vue.js Components Communication Patterns (without Vuex) - Part 3&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;&lt;a href="https://csdigitalnomad.medium.com/vue-js-components-communication-patterns-without-vuex-part-4-f99a17bd98f0" rel="noopener noreferrer"&gt;Vue.js Components Communication Patterns (without Vuex) - Part 4&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;&lt;a href="https://csdigitalnomad.medium.com/vue-js-components-communication-patterns-without-vuex-part-5-2cf6fb1c5e26" rel="noopener noreferrer"&gt;Vue.js Components Communication Patterns (without Vuex) - Part 5&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;&lt;a href="https://csdigitalnomad.medium.com/vue-js-components-communication-patterns-without-vuex-part-6-10e4e43f0ac7" rel="noopener noreferrer"&gt;Vue.js Components Communication Patterns (without Vuex) - Part 6&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;&lt;a href="https://csdigitalnomad.medium.com/vue-js-components-communication-patterns-without-vuex-part-7-15c5b786539e" rel="noopener noreferrer"&gt;Vue.js Components Communication Patterns (without Vuex) - Part 7&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>vue</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
