One way vs. two way binding in Vue

Vue supports two-way binding through the excellent v-model directive, and one-way binding using a :value= syntax. Both have their uses within a Vue component. There are good enough reasons to use one over the other.

First, let’s look at an example of two-way binding -

<template>
  <input v-model="message" />
</template>

<script>
  export default {
    data() {
      return { message: "hello" };
    }
  };
</script>

v-model is a short form of v-bind. The above statement is equivalent to -

<!-- ... code -->
<input v-bind:value="message" v-on:input="message =  $event.target.value" />
<!-- ... code -->

When you change message in input box, the variable value will change. If an external logic (or a computation) changes message, the input box value will change. So 2-way binding literally binds the DOM element to the variable value in ViewModel (you do remember that Vue is MVVM, don’t you :)).

Next, this is how we do one-way binding.

<template>
  <input :value="message" />
</template>

<script>
  export default {
    data() {
      return { message: "hello" };
    }
  };
</script>

As was the case in v-model, this is equivalent to -

<!-- ... code -->
<input v-bind:value="message" />
<!-- ... code -->

By this time you would probably understand that a : in binding context is always equal to v-bind:. Vue provides the shortcuts in form of v-model, @input etc.

In the above 1-way bind statement, whenever the message value in data changes, the input value will change. However, there is no functionality to update the data variable when input is changed (it just a ‘one-direction flow’).

At first, the two may seem confusing. Why go through the trouble of using a one-way binding? What is the advantage of one over the other? There are a few reasons -

Special Value Bindings

Consider this - you have to bind variable in the UI to a data variable. However, any updates should apply a complex set of rules before updating the original variable. There is no way to do this in v-model since it behaves like a simple = operator.

In the below example using Vuetify, password is a decrypted form of a hashed string. When password is updated, the string entered by user will be hashed and updated in the variable.

<template>
  <v-text-field
    name="pass"
    label="Enter password"
    :value="pass"
    @input="setHashedPass"
  ></v-text-field>
</template>

<script>
  export default {
    data() {
      return {
        pass: ""
      };
    },
    methods: {
      setHashedPass(value) {
        this.pass = hashFunction(value);
      }
    }
  };
</script>
Performance

One way binding is advantageous in terms of performance. Vue does not have to track changes to the variable in UI when there is one-way binding. So - if you don’t care about changes to the variable (e.g. a read-only field, or throw-away value), use 1-way rather than 2-way binding.

comments powered by Disqus