Componente de búsqueda sin rebote en Vue.js
La búsqueda es una funcionalidad esencial para la mayoría de las aplicaciones de la vida real y un desafío de entrevista de codificación muy común. Implementemos una aplicación simple que obtenga datos para una API para demostrar algunos conceptos básicos y mejores prácticas de Vue. Si solo está interesado en el ejemplo de la API de composición, continúe.
Interfaz de usuario
Simplifiquemos las cosas creando un formulario usando solo una entrada de búsqueda y un botón para enviarlo.
<template>
<form>
<input type="search" placeholder="Search for products..." />
<button>Search</button>
</form>
</template>
Vamos a presentar Vue. Necesitamos una forma de rastrear el valor de la entrada, y a v-modeles el caso de uso perfecto para eso. Además, necesitamos realizar la búsqueda cuando se hace clic en el botón. Podríamos usar un controlador de clic en el botón en sí, pero al usar el evento de envío en el formulario, tenemos soporte de teclado gratis. La búsqueda se realizará haciendo clic en el botón y enviando el formulario presionando la tecla Intro.
<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>
Para los datos, usaremos el servicio dummyJSON que devolverá algunos JSON ficticios y la API de recuperación nativa . Para obtener los datos, necesitamos crear un enlace en forma de https://dummyjson.com/products/search?q=Laptop&limit=5Lo hacemos en el ayudante getSearchUrl usando la funcionalidad nativa de URLSearchParams .
Establecemos la respuesta a una variable reactiva llamada productos.
<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>
Es posible que haya notado que realizaremos una búsqueda cada vez que se envíe el formulario. Esto podría desbordar nuestro servidor y causar un comportamiento extraño si algunas respuestas se cumplen en un orden diferente al que se enviaron. Para evitar esto, podemos introducir la eliminación de rebotes.
La eliminación de rebotes es una técnica que envuelve nuestra función con una función de proxy que, mientras se siga invocando, no se activará. La función se llamará después de que deje de llamarse durante una cantidad definida de milisegundos.
Podríamos implementar nuestra propia función de rebote , pero usaremos un paquete npm en su lugar.
La sintaxis se siente un poco antinatural, pero debería ser más clara después de ver la firma de la función de rebote. 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>
Buscar automáticamente
Tener un botón para buscar no es común hoy en día. Realicemos la búsqueda automáticamente usando un observador en su lugar.
Además, agregamos algunas validaciones en caso de que el término de búsqueda esté vacío o sea demasiado corto.
<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>
No hay nada emocionante en este componente, pero no podemos tener una función de búsqueda sin resultados.
<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>
Puede encontrar la solución final para un componente de búsqueda antirrebote mediante la API de opciones en el siguiente entorno limitado .
API de composición
Vue 3 está aquí, y el uso de la API de composición pronto será la norma. Convertir nuestras soluciones para usarlas será interesante. Vamos a hacer eso.
La conversión del componente Resultados de búsqueda es trivial ya que es solo un componente de presentación.
Todo permanece igual en la plantilla, y tenemos que usar el definePropsasistente interno script setuppara que la plantilla conozca los productos.
<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>
- Agregar
setupa la etiqueta del script - Declarar datos usando ref
- Actualice las referencias a los datos agregando .value
- Quitar
thistodo se puede acceder directamente - Declarar observador usando el
watchayudante
<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>
Puede encontrar la solución final para un componente de búsqueda antirrebote mediante la API de composición en el siguiente espacio aislado .
Conclusión
Así que aquí tienes. Un componente de búsqueda simple que usa antirrebote en los formatos API de Opciones y Composición. Toma tiempo acostumbrarse al nuevo formato, pero definitivamente es más limpio, y creo que pronto será la forma en que escribimos nuestros componentes.
Este artículo se inspiró en el anuncio de Vue 2022 Day #1 Challenge.

![¿Qué es una lista vinculada, de todos modos? [Parte 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)



































