methods, watchers и computed

Сравнение methods, watchers и computed

Методы лучше всего использовать в качестве обработчиков событий, происходящих в DOM, в ситуациях, когда вам нужно вызвать функцию или выполнить вызов API.

Все значения, возвращаемые методами, не кэшируются.

Например, вы можете создать действие, обозначенное @click, и сослаться на метод:

<template>
  <button @click="getDate">Click me</button>
</template>
<script>
  export default {
    methods: {
      getDate() {
        alert(Date.now())
      }
    }
  }
</script>

Этот блок кода будет отображать alert с текущим временем всякий раз, когда пользователь нажимает на кнопку Click me. Не следует использовать методы
для отображения вычисляемых данных, так как возвращаемое значение метода, в отличие от computed, не кэшируются, что может привести к снижению производительности в вашем приложении в случае неправильного использования.
Как уже упоминалось, computed лучше всего использовать при реагировании на обновления данных или для составления сложных выражений в вашем шаблоне. В следующем примере, если данные в animalList изменятся, computed свойство - animals, также будет обновляться, вырезая второй элемент из массива и
возвращает новое значение:

<template>
  <div>{{ animals }}</div>
</template>
<script>
  export default {
    data() {
      return {
        animalList: ['dog', 'cat']
      }
    },
  computed: {
    animals() {
      return this.animalList.slice(1)
    }
  }
 }
</script>

Реактивность делает computed свойства идеальными для составления новых переменных из существующих данных, например, когда вы ссылаетесь на конкретные ключи более крупного и сложного объекта.

Вычисляемые свойства также помогают повысить читабельность вашего template компонента и его логики. В следующем примере, мы выводим авторов двумя разными способами, но с вычисляемым свойством authorName вы можете составить условную логику, не раздувая HTML шаблон:

<template>
  <div>
    <p id="not-optimal">{{ authors[0].bio.name }}</p>
    <p id="optimal">{{ authorName }}</p>
  </div>
</template>
<script>
  export default {
    data() {
      return {
        authors: [
         {
           bio: {
             name: 'John',
             title: 'Dr.',
           }
         }
     ]
   }
  },
computed: {
  authorName () {
    return this.authors ? this.authors[0].bio.name : 'No Name'
  }
 }
}
</script>

Однако во многих случаях использование computed может быть излишним, например, когда вы хотите наблюдать только за вложенным свойством определенных данных, а не
за всем объектом. Или когда нужно послушать и выполнить действие при любых изменениях свойства данных или определенного ключа свойства, вложенного внутри
объекта свойства данных, а затем выполнить действие. В этом случае следует использовать watch.

<template>
  <div>
    <button @click="getNewName()">Click to generate name</button>
    <p v-if="author">{{ author }}</p>
  </div>
</template>
<script>
  export default {
    data() {
      return {
        data: {},
        author: '',
      }
    },
    watch: {
      data: function(newVal, oldVal) {
        this.author = newVal.first;
        alert('Name changed from ${oldVal.first} to ${newVal.first}')
    }
  },
  methods: {
    async getNewName() {
      await fetch('https://randomuser.me/api/').then(response =>response.json()).then(data => {
      this.data = data.results[0].name
    })
   },
  },
}
</script>

Упражнение

Попробуйте создать приложение, которое будет осуществлять поиск, и использованием methods, computed и watcher:

Methods vs watchers vs computed props

Решение:

<template>
  <div class="container">
    <h1>Methods vs watchers vs computed props</h1>
    <div class="col">
      <input type="text" placeholder="Search with method" v-model="input" @keyup="searchMethod"/>
      <ul>
        <li v-for="(item, i) in methodFilterList" :key="i">{{ item }}</li>
      </ul>
      </div>
      <div class="col">
        <input type="text" placeholder="Search with computed" v-model="input2" />
        <ul>
          <li v-for="(item, i) in computedList" :key="i">{{ item }}</li>
        </ul>
      </div>
      <div class="col">
        <input type="text" placeholder="Search with watcher" v-model="input3" />
        <ul>
          <li v-for="(item, i) in watchFilterList" :key="i">{{ item }}</li>
        </ul>
      </div>
    </div>
</template>
<script>
export default {
  data() {
    return {
      // Shared
      frameworkList: [
        "Vue",
        "React",
        "Backbone",
        "Ember",
        "Knockout",
        "jQuery",
        "Angular",
      ],
      // Method
      input: "",
      methodFilterList: [],
      // Computed
      input2: "",
      // Watcher
      input3: "",
      watchFilterList: [],
    };
  },
  created() {
    this.searchMethod();
  },
  watch: {
   input3: {
     handler() {
       this.watchFilterList = this.frameworkList.filter((item) =>
       item.toLowerCase().includes(this.input3.toLowerCase())
     );
   },
   immediate: true,
  },
  },
  computed: {
    computedList() {
      return this.frameworkList.filter((item) => {
      return item.toLowerCase().includes(this.input2.toLowerCase());
    });
  },
},
methods: {
  searchMethod() {
    this.methodFilterList = this.frameworkList.filter((item) =>
    item.toLowerCase().includes(this.input.toLowerCase()));
  },
  },
};
</script>
<style scoped>
.container {
  margin: 0 auto;
  padding: 30px;
  max-width: 600px;
  font-family: "Avenir", Helvetica, Arial, sans-serif;
}
.col {
  width: 33%;
  height: 100%;
  float: left;
}
input {
  padding: 10px 6px;
  margin: 20px 10px 10px 0;
}
</style>

В этом упражнении мы увидели, как можно создать отфильтрованный список, используя
methods, computed и watch.
В этом разделе кратко продемонстрированы три подхода. Каждый подход имеет
свои плюсы и минусы и выбор наиболее подходящего подхода для применения зависит от многих факторов.