Aprende a crear un campo de autocompletado fácilmente con el componente react-autocomplete.

Cómo crear un campo de texto con autocompletado sincrónico y asincrónico en ReactJS

Como todo usuario, suelo ser vago y no quiero teclear todo dentro de una entrada para buscar algo, al menos sabiendo eso cuando podemos aprovechar la tecnología para hacernos la vida más fácil. Es por eso que existen los campos de autocompletar, la idea es simple, escribe un texto que puede coincidir con una opción de la lista y puede seleccionarlo, para no escribir información incorrecta sobre algo, ya que puede recuperar todo de su servidor o localmente.

En este artículo le mostraremos cómo implementar un componente de autocompletar fácilmente en su proyecto para facilitar la vida de sus usuarios.

Requisitos

Para implementar de la forma más rápida y sencilla posible un componente de autocompletar, le recomendamos que utilice el react-autocompletemódulo. Este módulo ofrece un componente de autocompletado React (combobox) compatible con WAI-ARIA que se puede personalizar fácilmente de acuerdo con sus necesidades. Para usarlo, proceda con la instalación del módulo en su proyecto usando el siguiente comando usando NPM en su terminal:

npm install --save react-autocomplete

Después de la instalación, podrá importar los componentes Autocompletedesde 'react-autocomplete'. Para obtener más información sobre esta biblioteca, visite el repositorio oficial en Github aquí .

A. Crear un autocompletado sincrónico

Si está dispuesto a utilizar un campo de autocompletar que sugiera datos locales (una matriz de objetos ya disponible en la clase), solo necesita definir los datos dentro del estado de la clase y cargarlos en la propiedad de elementos del componente Autocompletar. Los datos estarán en un formato de matriz, conformado solo por objetos. Cada objeto es un elemento de la lista de autocompletar, los valores se pueden nombrar como desee (ya que puede definir qué propiedades del objeto se representan en el autocompletar). El siguiente ejemplo implementa 6 de los accesorios básicos del componente, definimos una devolución de llamada para las acciones básicas como cuando la entrada cambia o el usuario selecciona alguna opción del autocompletado.

Además, personalizamos la estructura de cada elemento renderizado usando la devolución de llamada renderItem y declaramos un valor inicial, que en este caso estará vacío usando la propiedad value del estado declarado:

import React from 'react';

// Importar el componente de autocompletar
import Autocomplete from 'react-autocomplete';

export default class App extends React.Component {

    constructor(props, context) {
        super(props, context);

        // Set initial State
        this.state = {
            // Valor actual del campo de selección
            value: "",
            // Datos que se procesarán en el autocompletado
            autocompleteData: [
                { 
                    label: 'Apple',
                    value: 1
                },
                { 
                    label: 'Microsoft',
                    value: 2
                },
                { 
                    label: 'Me, Myself and I',
                    value: 3
                }
            ]
        };

        // Vincular el contexto `this` a las funciones de la clase
        this.onChange = this.onChange.bind(this);
        this.onSelect = this.onSelect.bind(this);
        this.getItemValue = this.getItemValue.bind(this);
        this.renderItem = this.renderItem.bind(this);
    }
    
    /**
     * La devolución de llamada se activa cuando el usuario escribe en el campo de autocompletar
     * 
     * @param {Event} e JavaScript Event
     * @return {Event} El evento de JavaScript se puede utilizar como de costumbre.
     */
    onChange(e){
        this.setState({
            value: e.target.value
        });

        console.log("The Input Text has changed to ", e.target.value);
    }

    /**
     * La devolución de llamada se activa cuando cambia la entrada de autocompletar.
     * 
     * @param {Object} val Value returned by the getItemValue function.
     * @return {Nothing} No value is returned
     */
    onSelect(val){
        this.setState({
            value: val
        });

        console.log("Opción de 'base de datos' seleccionada: ", val);
    }

    /**
     * Defina el marcado de cada elemento renderizado del autocompletado.
     * 
     * @param {Object} item Objeto único de los datos que se pueden mostrar dentro del autocompletado
     * @param {Boolean} isHighlight declara si el elemento se ha resaltado o no.
     * @return {Markup} Component
     */
    renderItem(item, isHighlighted){
        return (
            <div style={{ background: isHighlighted ? 'lightgray' : 'white' }}>
                {item.label}
            </div>   
        ); 
    }

    /**
     * Defina qué propiedad de la fuente de autocompletar se mostrará al usuario.
     * 
     * @param {Object} item Single object from the data that can be shown inside the autocomplete
     * @return {String} val
     */
    getItemValue(item){
        // Obviamente, solo puede devolver la etiqueta o el componente que necesita mostrar
        // En este caso vamos a mostrar el valor y la etiqueta que muestra en la entrada
        // algo como "1 - Microsoft"
        return `${item.value} - ${item.label}`;
    }

    render() {
        return (
            <div>
                <Autocomplete
                    getItemValue={this.getItemValue}
                    items={this.state.autocompleteData}
                    renderItem={this.renderItem}
                    value={this.state.value}
                    onChange={this.onChange}
                    onSelect={this.onSelect}
                />
            </div>
        );
    }
}

La clase anterior generará un autocompletado muy simple que se ve así:

Sync Autocomplete Example React

B. Creación de un autocompletado asincrónico

Por lo general, un autocompletado también implementa una interfaz asíncrona, lo que significa que cuando el usuario escribe la entrada, alguna lógica se ejecuta en segundo plano y recupera cierta información del servidor. Gracias a la metodología React y al componente, esto no es tan difícil de lograr ya que usamos el estado de React para hacer el trabajo difícil por nosotros.

El proceso para implementar el autocompletado será el mismo que el síncrono, sin embargo, solo hay una cosa que cambia, la fuente de datos. Inicialmente, configuramos el autocompleteDataen una matriz vacía ya que se supone que debemos cargar esta información desde nuestro servidor. La lógica para cargar los datos remotos en el autocompletado es simple, solo necesitamos actualizar el estado de autocompleteDatacon los datos remotos y ¡listo! Obviamente, la estructura de los datos debe coincidir con la declarada en nuestra lógica localmente (para obtener etiquetas y valores, etc.). En el siguiente ejemplo, la función para recuperar los datos de la fuente remota esretrieveDataAsynchronously, esta función se activa dentro de la devolución de llamada onChange que obviamente debe declararse. La función recibe como primer argumento el texto actual de la entrada, que será utilizado por la lógica del lado del servidor para enviar algunos datos de acuerdo a lo solicitado por el usuario:

import React from 'react';

// Importar el componente de autocompletar
import Autocomplete from 'react-autocomplete';

export default class App extends React.Component {

    constructor(props, context) {
        super(props, context);

        // Establecer estado inicial
        this.state = {
            // Valor actual del campo de selección
            value: "",
            // Datos que se procesarán en el autocompletado
            // Como es asincrónico, inicialmente está vacío
            autocompleteData: []
        };

        // Vincular el contexto `this` a las funciones de la clase
        this.onChange = this.onChange.bind(this);
        this.onSelect = this.onSelect.bind(this);
        this.getItemValue = this.getItemValue.bind(this);
        this.renderItem = this.renderItem.bind(this);
        this.retrieveDataAsynchronously = this.retrieveDataAsynchronously.bind(this);
    }


    /**
     * Actualiza el estado de los datos de autocompletar con los datos remotos obtenidos a través de AJAX.
     * 
     * @param {String} searchText content of the input that will filter the autocomplete data.
     * @return {Nothing} The state is updated but no value is returned
     */
    retrieveDataAsynchronously(searchText){
        let _this = this;

        // Url of your website that process the data and returns a
        let url = `mywebsite/searchApi?query=${searchText}`;
        
        // Configure a basic AJAX request to your server side API
        // that returns the data according to the sent text
        let xhr = new XMLHttpRequest();
        xhr.open('GET', url, true);
        xhr.responseType = 'json';
        xhr.onload = () => {
            let status = xhr.status;

            if (status == 200) {
                // In this example we expects from the server data with the structure of:
                // [
                //    {
                //        label: "Some Text",
                //        value: 1,
                //    },
                //    {
                //        label: "Some Other Text",
                //        value: 1,
                //    },
                // ]
                // But you can obviously change the render data :)

                // Update the state with the remote data and that's it !
                _this.setState({
                    autocompleteData: xhr.response
                });

                // Show response of your server in the console
                console.log(xhr.response);
            } else {
                console.error("Cannot load data from remote source");
            }
        };

        xhr.send();
    }
    
    /**
     * Callback triggered when the user types in the autocomplete field
     * 
     * @param {Event} e JavaScript Event
     * @return {Event} Event of JavaScript can be used as usual.
     */
    onChange(e){
        this.setState({
            value: e.target.value
        });

        /**
         * Handle the remote request with the current text !
         */
        this.retrieveDataAsynchronously(e.target.value);

        console.log("The Input Text has changed to ", e.target.value);
    }

    /**
     * Callback triggered when the autocomplete input changes.
     * 
     * @param {Object} val Value returned by the getItemValue function.
     * @return {Nothing} No value is returned
     */
    onSelect(val){
        this.setState({
            value: val
        });

        console.log("Option from 'database' selected : ", val);
    }

    /**
     * Define the markup of every rendered item of the autocomplete.
     * 
     * @param {Object} item Single object from the data that can be shown inside the autocomplete
     * @param {Boolean} isHighlighted declares wheter the item has been highlighted or not.
     * @return {Markup} Component
     */
    renderItem(item, isHighlighted){
        return (
            <div style={{ background: isHighlighted ? 'lightgray' : 'white' }}>
                {item.label}
            </div>   
        ); 
    }

    /**
     * Define which property of the autocomplete source will be show to the user.
     * 
     * @param {Object} item Single object from the data that can be shown inside the autocomplete
     * @return {String} val
     */
    getItemValue(item){
        // You can obviously only return the Label or the component you need to show
        // In this case we are going to show the value and the label that shows in the input
        // something like "1 - Microsoft"
        return `${item.value} - ${item.label}`;
    }

    render() {
        return (
            <div>
                <Autocomplete
                    getItemValue={this.getItemValue}
                    items={this.state.autocompleteData}
                    renderItem={this.renderItem}
                    value={this.state.value}
                    onChange={this.onChange}
                    onSelect={this.onSelect}
                />
            </div>
        );
    }
}

Cuando el usuario escribe en el autocompletado, el texto dado se envía al servidor con una solicitud AJAX y debe devolver como respuesta una matriz con algunos datos que coinciden con el texto proporcionado por el usuario. El estado se actualiza con los datos enviados desde el servidor y el usuario puede elegir una opción. Tenga en cuenta que la implementación aquí crea una solicitud ajax que se ejecuta cada vez que el usuario presiona una tecla, lo que significa muchas solicitudes, por lo que es posible que desee eliminar el rebote de la función de alguna manera . Recuerda que puedes personalizar la entrada y los elementos de autocompletar como desees usando solo CSS modificando la opción menuStyle .

Que te diviertas ❤️!


Interesado en la programación desde los 14 años, Carlos es un programador autodidacta, fundador y autor de la mayoría de los artículos de Our Code World.

Conviertete en un programador más sociable

Patrocinadores