Entprellte Suchkomponente in Vue.js

Dec 10 2022
Von der Options-API zur Kompositions-API
Die Suche ist eine wesentliche Funktion für die meisten realen Anwendungen und eine sehr häufige Herausforderung bei der Programmierung von Interviews. Lassen Sie uns eine einfache Anwendung implementieren, die Daten für eine API abruft, um einige grundlegende Vue-Konzepte und Best Practices zu demonstrieren.

Die Suche ist eine wesentliche Funktion für die meisten realen Anwendungen und eine sehr häufige Herausforderung bei der Programmierung von Interviews. Lassen Sie uns eine einfache Anwendung implementieren, die Daten für eine API abruft, um einige grundlegende Vue-Konzepte und Best Practices zu demonstrieren. Wenn Sie nur am Beispiel der Kompositions-API interessiert sind, überspringen Sie es.

Benutzeroberfläche

Lassen Sie uns die Dinge einfach halten, indem wir ein Formular erstellen, das nur eine Sucheingabe und eine Schaltfläche zum Senden verwendet.

<template>
  <form>
    <input type="search" placeholder="Search for products..." />
    <button>Search</button>
  </form>
</template>

Lassen Sie uns Vue vorstellen. Wir brauchen eine Möglichkeit, den Wert der Eingabe zu verfolgen, und a v-modelist der perfekte Anwendungsfall dafür. Außerdem müssen wir die Suche durchführen, wenn auf die Schaltfläche geklickt wird. Wir könnten einen Click-Handler auf der Schaltfläche selbst verwenden, aber wenn wir stattdessen das Submit-Ereignis im Formular verwenden, haben wir kostenlose Tastaturunterstützung. Die Suche wird sowohl durch Klicken auf die Schaltfläche als auch durch Drücken der Eingabetaste durchgeführt.

<template>
  <form @submit.prevent="performSearch">
    <input
      type="search"
      placeholder="Search for products..."
      v-model="searchTerm"
    />
    <button>Search</button>
  </form>
</template>

<script>
export default {
  name: "TheSearch",
  data() {
    return {
      searchTerm: "",
    };
  },
  methods: {
    performSearch() {
      // TODO
      // Perform search here
    },
  },
};
</script>

Für die Daten verwenden wir den DummyJSON -Dienst, der Dummy-JSON und die native Abruf-API zurückgibt . Um die Daten abzurufen, müssen wir einen Link in der Form https://dummyjson.com/products/search?q=Laptop&limit=5We do that im getSearchUrl-Hilfsprogramm erstellen, indem wir die native URLSearchParams- Funktion verwenden.

Wir setzen die Antwort auf eine reaktive Variable namens Produkte.

<script>
export default {
  name: "TheSearch",
  data() {
    return {
      searchTerm: "",
      products: [],
    };
  },
  methods: {
    async performSearch() {
      const searchUrl = this.getSearchUrl();
      const response = await (await fetch(searchUrl)).json();

      this.products = response.products;
    },
    getSearchUrl() {
      const url = "https://dummyjson.com/products/search";
      const params = {
        q: this.searchTerm,
        limit: 5,
      };

      const searchParams = new URLSearchParams(params);
      return `${url}?${searchParams}`;
    },
  },
};
</script>

Sie haben vielleicht bemerkt, dass wir jedes Mal, wenn das Formular gesendet wird, eine Suche durchführen. Dies könnte unseren Server überlaufen lassen und ein seltsames Verhalten verursachen, wenn einige Antworten in einer anderen Reihenfolge ausgeführt werden, als sie gesendet wurden. Um dies zu vermeiden, können wir eine Entprellung einführen.

Entprellen ist eine Technik, die unsere Funktion mit einer Proxy-Funktion umschließt, die nicht ausgelöst wird, solange sie weiterhin aufgerufen wird . Die Funktion wird aufgerufen, nachdem sie für eine definierte Anzahl von Millisekunden nicht mehr aufgerufen wird.

Wir könnten unsere eigene Debounce-Funktion implementieren , aber wir werden stattdessen ein npm-Paket verwenden.

Die Syntax fühlt sich etwas unnatürlich an, sollte aber klarer sein, nachdem Sie die Signatur der Debounce-Funktion gesehen haben debounce(fn, wait, [ immediate || false ])

<script>
import { debounce } from "debounce";

export default {
 ...
  methods: {
    performSearch: debounce(
      async function () {
        const searchUrl = this.getSearchUrl();
        const response = await (await fetch(searchUrl)).json();

        this.products = response.products;
      },
      600
    ),
   ...
  },
};
</script>

Automatisch suchen

Eine Schaltfläche zum Suchen ist heutzutage nicht mehr üblich. Lassen Sie uns die Suche stattdessen automatisch mit einem Watcher durchführen.

Zusätzlich haben wir einige Validierungen hinzugefügt, falls der Suchbegriff leer oder zu kurz ist.

<script>
  ...
  watch: {
    searchTerm() {
      this.performSearch();
    },
  },
  methods: {
    performSearch: debounce(async function () {
      if (this.searchTerm === "") {
        this.products = [];
        return;
      }
      if (this.searchTerm.length < 2) {
        return;
      }
      const searchUrl = this.getSearchUrl();
      const response = await (await fetch(searchUrl)).json();

      this.products = response.products;
    }, 600),
   ...
</script>

Nichts Aufregendes an dieser Komponente, aber wir können keine Suchfunktion ohne Ergebnisse haben.

<template>
  <section>
    <h2>Products</h2>
    <div v-for="product in products" :key="product.id">
      <img :src="product.thumbnail" alt="product.title" />
      <h5>
        {{ product.title }}
      </h5>
      <p>
        {{ product.description }}
      </p>
      <hr />
    </div>
  </section>
</template>

<script>
export default {
  name: "SearchResults",
  props: ["products"],
};
</script>

<template>
    ...
    <SearchResults v-if="products.length" :products="products" />
</template>

<script>
import SearchResults from "./SearchResults.vue";

export default {
  name: "TheSearch",
  components: {
    SearchResults,
  },
  ...
};
</script>

Die endgültige Lösung für eine entprellte Suchkomponente finden Sie unter Verwendung der Options-API in der folgenden Sandbox .

Kompositions-API

Vue 3 ist da und die Verwendung der Kompositions-API wird bald die Norm sein. Es wird interessant sein, unsere Lösungen zu konvertieren, um es zu verwenden. Lass uns das tun.

Die Konvertierung der Suchergebniskomponente ist trivial, da es sich nur um eine Präsentationskomponente handelt.

In der Vorlage bleibt alles gleich, und wir müssen den definePropsHelfer darin verwenden script setup, um die Vorlage auf die Produkte aufmerksam zu machen.

<template>
  <section>
    <h2>Products</h2>
    <div v-for="product in products" :key="product.id">
      <img :src="product.thumbnail" alt="product.title" />
      <h5>
        {{ product.title }}
      </h5>
      <p>
        {{ product.description }}
      </p>
      <hr />
    </div>
  </section>
</template>

<script setup>
defineProps(["products"]);
</script>

  • setupZum script-Tag hinzufügen
  • Deklarieren Sie Daten mit ref
  • Aktualisieren Sie die Verweise auf Daten, indem Sie .value hinzufügen
  • Auf alles entfernen thiskann direkt zugegriffen werden
  • Deklarieren Sie den Beobachter mit dem watchHelfer

<template>
  // Remains the same
</template>

<script setup>
import { debounce } from "debounce";
import { ref, watch } from "vue";
import SearchResults from "./SearchResults.vue";

const searchTerm = ref("");
const products = ref([]);

const getSearchUrl = () => {
  const url = "https://dummyjson.com/products/search";
  const params = {
    q: searchTerm.value,
    limit: 5,
  };
  const searchParams = new URLSearchParams(params);
  return `${url}?${searchParams}`;
};

const performSearch = debounce(async () => {
  if (searchTerm.value === "") {
    products.value = [];
    return;
  }
  if (searchTerm.value.length < 2) {
    return;
  }
  const searchUrl = getSearchUrl();
  const response = await (await fetch(searchUrl)).json();

  products.value = response.products;
}, 600);

watch(searchTerm, () => {
  performSearch();
});
</script>

Die endgültige Lösung für eine entprellte Suchkomponente mit Kompositions-API finden Sie in der folgenden Sandbox .

Fazit

Also los geht's. Eine einfache Suchkomponente, die Debounce sowohl in den Formaten Options als auch Composition API verwendet. Das neue Format braucht etwas Zeit, um sich daran zu gewöhnen, aber es ist definitiv sauberer, und ich glaube, dass wir bald unsere Komponenten so schreiben werden.

Dieser Artikel wurde von der Advert Of Vue 2022 Day #1 Challenge inspiriert.