Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to bind attributes with v-bind only once?

I am using vue-i18n for localization. When I want to translate input placeholders, as in:

<input type="text" v-model="someValue" :placeholder="$t('translation.string')">

I have to use the $t() function which is executed on every re-render (library docs mention is as well). This adds thousands of unnecessary function calls in my simple booking form, which I'd like to avoid.

Is there a way to bind the attribute only once? The translated value does not change throughout the lifecycle of Vue instance. v-once is not what I am looking for, since I want to keep the component/node reactive, and only 'hardcode' the attribute.

I know I could achieve what I need by simply storing the translated strings in the data object, but I'd like to know if there is an alternative, simpler solution (not requiring massive code duplication).

like image 658
Amade Avatar asked Mar 01 '18 15:03

Amade


People also ask

How do you use V-bind?

You can use v-bind to bind built-in HTML attributes to JavaScript expressions. For example, you can make a link whose href is bound to a data field. When the link field changes, so does the href . const app = new Vue({ data: () => ({ link: 'http://google.com' }), // Initially, the link will go to Google...

What does V-bind Attrs do?

Remember that v-bind without an argument binds all the properties of an object as attributes of the target element.

What is V once?

The v-once directive is a Vue. js directive that is used to avoid unwanted re-renders of an element. It treats the element as a static content after rendering it once for the first time. This improves performance as it does not have to be rendered again.

Does Vue JS have two-way data binding?

Vue is also perfectly capable of powering sophisticated Single-Page Applications in combination with modern tooling and supporting libraries. The v-model directive makes two-way binding between a form input and app state very easy to implement.

How do I bind data to an attribute?

This means that you can bind data to an attribute or event using v-bind or : for short. Doing this you can manipulate the display of a selector, content of an attribute and more. In this example we simply add a title attribute text to the title tag of a button with v-bind.

How do I bind to an attribute in Vue?

V-Bind – Attribute Class Binding with Vue. V-Bind is a Vue kind of way to bind data to attributes or classes. This means that you can bind data to an attribute or event using v-bind or : for short. Doing this you can manipulate the display of a selector, content of an attribute and more.

What is V-bind in Vue JS?

V-Bind is a Vue kind of way to bind data to attributes or classes. This means that you can bind data to an attribute or event using v-bind or : for short.

How do you bind one way in JavaScript?

There are two broad use cases for this one-way data binding: You can use v-bind to bind built-in HTML attributes to JavaScript expressions. For example, you can make a link whose href is bound to a data field. When the link field changes, so does the href.


1 Answers

A computed property will do what you're looking for, since they only trigger a re-run when their dependencies change. Since this.$t('LOCALE.STRING') doesn't change unless your locale changes, you're guaranteed only a single run, after which the value will be cached by Vue for subsequent renders.

<template>
  ...
  <input
    ...
    :placeholder="translatedPlaceholder"
  >
  ...
</template>

<script>
  ...
  computed: {
    translatedPlaceholder() {
      return $t('translation.string');
    },
  },
  ...
</script>

The awesome part about this solution is that if the locale does change, then Vue will indeed refresh the computed property, updating it to the correct value.


I've put together an interactive snippet to help demonstrate this syntax, if you're looking for a more extensive example.

The snippet includes a simple localized greeting followed by a random number in a <p> tag, with two buttons. The localized string in the text is pulled from a computed property.

The first button will generate a new number, causing the <p> to re-render in the DOM.
The second button will switch the locale, causing Vue-i18n to refresh the localized string.

Whenever the computed localization property is re-executed, it will log to console.
I also set the script up to log to console whenever Vue updates the DOM too.

const messages = {
  en: {
    "greeting": 'Hello!',
  },
  es: {
    "greeting": '¡Hola!',
  },
};

new Vue({ 
  i18n: new VueI18n({
    locale: 'en',
    messages,
  }),
  data() {
    return {
      num: 1,
    }
  },
  computed: {
    localizedGreeting() {
      console.log('Computed executed');
      return this.$t('greeting');
    },
  },
  methods: {
    swapLocale() {
      this.$i18n.locale = (this.$i18n.locale == 'en' ? 'es' : 'en');
    },
    randomNum() {
      this.num = Math.floor(Math.random() * 10000);
    },
  },
  updated() {
    console.log('DOM updated');
  },
}).$mount('#app')
.as-console-wrapper {
  max-height: 120px !important;
}
<script src="https://unpkg.com/vue@2/dist/vue.min.js"></script>
<script src="https://unpkg.com/vue-i18n@8"></script>

<div id="app">
  <p>{{ `${localizedGreeting} #${num}` }}</p>
  <button @click="randomNum()">Re-render Greeting</button>
  <button @click="swapLocale">Swap Greeting Locale</button>
</div>

As you can see, re-rendering doesn't cause the computed property to re-execute, but swapping the locale does, which is exactly what we're looking for here.


As a final note– while there is technically a performance hit in your original code, since you're re-executing $t() calls, it's worth bearing in mind that the actual performance hit is probably tiny. Don't trade simplicity for performance gains unless it really makes sense.

Remember, premature optimization is the root of all evil!

like image 153
zcoop98 Avatar answered Sep 17 '22 21:09

zcoop98