Vue.js Components Communication Patterns (without Vuex) - Part 1
Tags: javascript, vue, webdev
Published: 2021-11-22 22:34:05

***Custom v-model and .sync patterns***

## About this series
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 **building a UI library or a state management library**, Vuex is not suitable anymore, and we need to utilize the build-in mechanism of Vue itself.

## Custom v-model pattern
Here we have two components - `Parent` and `ChildA`:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ebqi9w3tfkvxl5m4g7p5.png)

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

Now let's look at `ChildA`:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kdvb1zasdsnrrve5o4k3.png)

`ChildA` also has a reactive data field named `desserts` and its value is from the prop `value` that `Parent` 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.

This is how the page looks at the moment:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8t9grvg41wm1h5v5ccho.png)


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

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hir5qbqginb1f1103f9z.png)

This pattern can make sure some data in `Parent` and `ChildA` is "in sync". Data still flows one-way as we can clearly see above. 

We can also make the code a bit more concise by writing the function inline:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xlwq00ku1y5a4tr0spga.png)

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: `v-model`. If we replace the `<ChildA>` tag in `Parent` with this one:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5vfdtp60pxv79hz86sv8.png)

We get the exact same result.

In addition, you can change the prop and event name using the `model` option [https://vuejs.org/v2/api/#model](https://vuejs.org/v2/api/#model).


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

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hc13i4u9xyfxbpdo79hg.png)

As the event name is changed, in `ChildA` now it needs to emit the new event name to trigger the event:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/szzt1y2i4mn4iss1g0ph.png)

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

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8f2hia91cq5nid9xtsjk.png)

The result is the same.


## What's under the hood
When Vue uses its `compileToFunctions` function to compile the `<template>` of a component:
* for any `v-model` in the `<template>`, it will generate `v-bind:value="xxx"` and `v-on:input="val => this.xxx = val"`.
* for any `v-bind:value.sync="xxx"` in the `<template>`, it will generate `v-bind:value="xxx"` and `v-on:update:value="val => this.xxx = val"`.
* for any event bound onto a child component tag:
```javascript
    <Child
      @anyEvent="parentUpdate"
    />
```
it will generate an object like so: `{anyEvent: parentUpdate}`, and this object will be passed onto the Child component instance (of `VueComponent` type). When the Child component gets this object, it will mount it onto itself via `this.$on('anyEvent', parentUpdate)`. This way, the Child component can trigger its `anyEvent` event via `this.emit('anyEvent', args)` ( 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.


## Conclusion
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 [Part 2](https://csdigitalnomad.medium.com/vue-js-components-communication-patterns-without-vuex-part-2-7f9c0bc132a2) of this series is about.

Also check out the rest articles in this Vue.js components patterns series:

***[Vue.js Components Communication Patterns (without Vuex) - Part 2](https://csdigitalnomad.medium.com/vue-js-components-communication-patterns-without-vuex-part-2-7f9c0bc132a2)***

***[Vue.js Components Communication Patterns (without Vuex) - Part 3](https://csdigitalnomad.medium.com/vue-js-components-communication-patterns-without-vuex-part-3-5ccfdbe3ecfa)***

***[Vue.js Components Communication Patterns (without Vuex) - Part 4](https://csdigitalnomad.medium.com/vue-js-components-communication-patterns-without-vuex-part-4-f99a17bd98f0)***

***[Vue.js Components Communication Patterns (without Vuex) - Part 5](https://csdigitalnomad.medium.com/vue-js-components-communication-patterns-without-vuex-part-5-2cf6fb1c5e26)***

***[Vue.js Components Communication Patterns (without Vuex) - Part 6](https://csdigitalnomad.medium.com/vue-js-components-communication-patterns-without-vuex-part-6-10e4e43f0ac7)***

***[Vue.js Components Communication Patterns (without Vuex) - Part 7](https://csdigitalnomad.medium.com/vue-js-components-communication-patterns-without-vuex-part-7-15c5b786539e)***