Библиотека Awesomplete изначально разработана как лёгкий независимый модуль для работы с автодополнением в обычном DOM-окружении. В контексте React она не теряет своей ценности, но требует правильного способа интеграции, поскольку React управляет DOM декларативно, а Awesomplete — императивно.
Ключевая задача при использовании Awesomplete в React — синхронизировать жизненный цикл компонента с инициализацией, обновлением и уничтожением экземпляра автодополнения.
React-хук useRef используется для получения прямого
доступа к DOM-элементу input, а useEffect — для создания и
управления экземпляром Awesomplete.
import React, { useEffect, useRef } from "react";
import Awesomplete from "awesomplete";
import "awesomplete/awesomplete.css";
function AutocompleteInput({ list }) {
const inputRef = useRef(null);
const awesompleteRef = useRef(null);
useEffect(() => {
if (!inputRef.current) return;
awesompleteRef.current = new Awesomplete(inputRef.current, {
list: list,
minChars: 1,
maxItems: 10,
autoFirst: true
});
return () => {
awesompleteRef.current = null;
};
}, []);
return <input ref={inputRef} />;
}
Важный момент заключается в том, что Awesomplete не знает о React-рендере. Поэтому инициализация происходит только после монтирования DOM-элемента.
Частая проблема — динамическое обновление списка подсказок.
Awesomplete не реагирует автоматически на изменение props, поэтому
необходимо вручную обновлять list.
useEffect(() => {
if (awesompleteRef.current) {
awesompleteRef.current.list = list;
}
}, [list]);
Такой подход позволяет синхронизировать внешний источник данных с внутренним состоянием автодополнения без пересоздания экземпляра.
React часто использует контролируемые компоненты, где значение input хранится в state. Awesomplete может конфликтовать с таким подходом, если не учитывать порядок обновлений.
import React, { useState, useRef, useEffect } from "react";
import Awesomplete from "awesomplete";
function ControlledAutocomplete({ suggestions }) {
const [value, setValue] = useState("");
const inputRef = useRef(null);
const awesompleteRef = useRef(null);
useEffect(() => {
if (!inputRef.current) return;
awesompleteRef.current = new Awesomplete(inputRef.current, {
list: suggestions
});
inputRef.current.addEventListener("awesomplete-selectcomplete", (e) => {
setValue(e.text.value);
});
return () => {
awesompleteRef.current = null;
};
}, [suggestions]);
return (
<input
ref={inputRef}
value={value}
onCha nge={(e) => setValue(e.target.value)}
/>
);
}
Здесь важен момент: событие awesomplete-selectcomplete
используется для синхронизации выбора с React state.
Awesomplete напрямую изменяет DOM, добавляя список подсказок рядом с input. React при этом не контролирует эти элементы.
Чтобы избежать конфликтов:
Пример правильного управления жизненным циклом:
useEffect(() => {
if (!inputRef.current) return;
const instance = new Awesomplete(inputRef.current, { list: suggestions });
awesompleteRef.current = instance;
return () => {
awesompleteRef.current = null;
};
}, []);
Awesomplete предоставляет методы управления поведением выпадающего списка, которые можно использовать внутри React-логики.
awesompleteRef.current.open();
awesompleteRef.current.close();
awesompleteRef.current.evaluate();
В React это часто связывается с дополнительными эффектами:
useEffect(() => {
if (value.length >= 2) {
awesompleteRef.current?.evaluate();
}
}, [value]);
Такой подход позволяет вручную контролировать момент появления подсказок.
При работе с API список подсказок часто формируется динамически. Awesomplete поддерживает функцию вместо массива.
useEffect(() => {
if (!inputRef.current) return;
awesompleteRef.current = new Awesomplete(inputRef.current, {
list: (text, callback) => {
fetch(`/api/suggest?q=${text}`)
.then(res => res.json())
.then(data => callback(data));
}
});
}, []);
Этот режим позволяет реализовать серверное автодополнение без дополнительной логики в React.
При частых изменениях списка или значения input важно избегать пересоздания Awesomplete.
Практика:
useReflistuseEffect(() => {
if (awesompleteRef.current) {
awesompleteRef.current.list = suggestions;
}
}, [suggestions]);
Это снижает нагрузку и исключает мерцание UI.
Awesomplete генерирует события, которые можно использовать для расширения логики приложения.
Основные события:
awesomplete-selectawesomplete-selectcompleteawesomplete-openawesomplete-closeПример обработки:
useEffect(() => {
const input = inputRef.current;
if (!input) return;
const handler = (e) => {
console.log("Выбран элемент:", e.text.value);
};
input.addEventListener("awesomplete-selectcomplete", handler);
return () => {
input.removeEventListener("awesomplete-selectcomplete", handler);
};
}, []);
Такой механизм позволяет интегрировать Awesomplete в архитектуру событий React без потери контроля.
Для масштабируемых приложений логично выделить обёртку над Awesomplete.
function useAwesomplete(inputRef, options) {
const instanceRef = useRef(null);
useEffect(() => {
if (!inputRef.current) return;
instanceRef.current = new Awesomplete(inputRef.current, options);
return () => {
instanceRef.current = null;
};
}, []);
useEffect(() => {
if (instanceRef.current && options.list) {
instanceRef.current.list = options.list;
}
}, [options.list]);
return instanceRef;
}
Такой хук упрощает повторное использование логики автодополнения в разных компонентах.
React StrictMode в режиме разработки может вызывать двойное монтирование компонентов. Это приводит к повторной инициализации Awesomplete, если не предусмотрена очистка.
Корректное управление:
useEffectТакие ошибки приводят к утечкам памяти, дублированию DOM-элементов и неконсистентному поведению автодополнения.
Awesomplete работает только в браузерной среде. При использовании SSR (например, в Next.js) требуется условная инициализация:
useEffect(() => {
if (typeof window === "undefined") return;
if (!inputRef.current) return;
awesompleteRef.current = new Awesomplete(inputRef.current, {
list: suggestions
});
}, []);
Это предотвращает ошибки гидратации и обращения к
document на сервере.