Изменения в API между версиями

В разных поколениях Tom Select наблюдается последовательный переход от модели, унаследованной от Selectize, к более модульной и предсказуемой архитектуре. Основной акцент смещается от «монолитного» объекта с неявными побочными эффектами к более управляемому состоянию компонента и явным контрактам методов.

Ключевое изменение — разделение внутреннего состояния (items, options, settings) и публичного API, который перестаёт быть прямым отражением внутренних структур и становится стабилизированным интерфейсом.


Инициализация компонента

Ранние версии предполагали относительно гибкую, но не всегда предсказуемую инициализацию через конструктор:

new TomSelect('#select', {
  create: true,
  maxItems: 3
});

В более поздних версиях поведение инициализации стало строже:

  • усилилась нормализация входных данных;
  • изменения DOM до инициализации стали менее допустимыми;
  • добавилась более явная обработка уже инициализированных элементов;
  • расширился жизненный цикл с предсказуемыми стадиями (setup → load → refresh).

Особое значение приобрела стабильность повторной инициализации: попытки повторно вызвать конструктор на одном элементе теперь обрабатываются более строго, с предотвращением дублирования инстанса.


Работа с выбранными значениями (items vs value)

Одним из наиболее заметных изменений между версиями стало уточнение модели данных.

Ранее:

  • value часто использовался как основной источник состояния;
  • items воспринимался как вспомогательное представление.

Позднее API разделяет эти понятия более строго:

  • items — внутренний список выбранных ключей;
  • getValue() — публичный метод получения текущего значения;
  • setValue() — установка состояния с полной перерисовкой.

Изменилось поведение мультивыбора:

control.addItem(value);
control.removeItem(value);

В новых версиях эти методы стали синхронно обновлять внутреннее состояние и UI без необходимости ручного вызова refresh-методов, которые ранее часто требовались.

Также изменилось поведение очистки:

  • clear() теперь гарантированно сбрасывает состояние и триггерит события изменения;
  • в старых реализациях очистка могла оставлять «висящие» элементы UI при кастомных рендерах.

Изменения в управлении методами API

Существенная часть миграции затрагивает методы управления состоянием компонента.

Добавление и удаление элементов

Ранее добавление значения часто требовало ручного контроля дубликатов:

addItem(value, silent);

Поведение параметра silent в новых версиях стало более предсказуемым: он подавляет события, но не отменяет внутреннюю логику перерасчёта состояния.

Удаление элементов стало менее «опасным»:

removeItem(value, silent);

В старых версиях удаление могло приводить к несогласованности между input value и визуальным состоянием при кастомных рендерах. В обновлённой архитектуре это устранено за счёт унифицированного слоя синхронизации.


Обновление состояния

Метод setValue() претерпел важную эволюцию:

  • раньше он часто работал как «мягкое обновление»;
  • теперь — это полноценная операция перезаписи состояния.

При вызове:

control.setValue(['a', 'b']);

выполняется:

  • очистка текущих значений;
  • валидация новых значений;
  • пересборка UI;
  • синхронизация с исходным <select>.

Система событий

Модель событий в Tom Select эволюционировала от простого набора callback’ов к более структурированной event-driven системе.

Основные изменения:

  • расширение набора событий;
  • унификация аргументов event handlers;
  • введение более стабильного порядка вызовов.

Примеры событий:

control.on('change', value => {});
control.on('item_add', value => {});
control.on('item_remove', value => {});
control.on('dropdown_open', () => {});
control.on('dropdown_close', () => {});

Ключевое изменение — согласованность:

  • события теперь вызываются после завершения внутренней транзакции состояния;
  • исключены промежуточные состояния, ранее доступные через нестабильные хуки.

Особое внимание уделено событию change: оно стало строго отражать финальное состояние после всех преобразований.


Плагины и расширяемость

Система плагинов претерпела архитектурное переосмысление.

В ранних версиях:

  • плагины часто напрямую модифицировали прототип;
  • отсутствовала строгая изоляция;
  • возможны конфликты между расширениями.

В новых версиях:

  • плагины регистрируются через единый механизм;
  • каждый плагин получает доступ к экземпляру через контролируемый контекст;
  • порядок подключения становится значимым.

Пример регистрации:

TomSelect.define('plugin_name', function(options) {
  return {
    init() {},
    destroy() {}
  };
});

Изменения:

  • добавлен предсказуемый lifecycle плагина (init, destroy);
  • усилена изоляция состояния;
  • снижена вероятность побочных эффектов между плагинами.

Рендеринг и кастомизация UI

Система render подверглась значительным изменениям.

Ранее:

render: {
  option(data, escape) {}
}

Проблема старого подхода заключалась в нестрогом контракте: структура data могла меняться между версиями без явной фиксации.

В новых версиях:

  • усилилась типизация входных данных;
  • стандартизированы поля объекта data;
  • поведение escape-функций стало консистентным.

Особое внимание уделено:

  • option
  • item
  • option_create
  • loading

Теперь рендеринг строго отделён от логики выбора, что уменьшает вероятность рассинхронизации UI и состояния.


Асинхронная загрузка данных

Механизм load в старых версиях был гибким, но сложным в контроле.

Ранее:

load: function(query, callback) {}

Проблемы:

  • отсутствие единых правил кеширования;
  • сложность управления race conditions;
  • ручное управление отменой запросов.

В обновлённых версиях:

  • введена более строгая обработка callback;
  • добавлена внутренняя защита от устаревших ответов;
  • улучшена интеграция с fetch-подобными API.

Изменилось поведение:

  • результаты старых запросов автоматически игнорируются при новом вводе;
  • предотвращается перезапись состояния «устаревшими» ответами.

Изменения в жизненном цикле инстанса

Жизненный цикл стал более формализованным:

  • создание инстанса;
  • инициализация DOM;
  • загрузка данных;
  • готовность к взаимодействию;
  • разрушение инстанса.

Метод destroy() стал более надёжным:

  • очищает event listeners;
  • восстанавливает исходный <select>;
  • удаляет добавленные DOM-узлы;
  • предотвращает утечки памяти, характерные для ранних версий.

Совместимость и миграционные изменения API

При переходе между версиями наблюдается несколько устойчивых категорий изменений:

1. Переименование и нормализация методов

Некоторые методы сохранили смысл, но изменили внутреннюю реализацию:

  • улучшена предсказуемость возвращаемых значений;
  • устранены неоднозначные побочные эффекты.

2. Изменение поведения по умолчанию

Значительная часть миграционных проблем связана не с удалением API, а с изменением дефолтных параметров:

  • create
  • maxItems
  • persist
  • closeAfterSelect

Эти параметры стали более строго интерпретироваться, без «неявных» fallback-значений.

3. Ужесточение валидации

В новых версиях:

  • запрещены неконсистентные состояния;
  • входные данные нормализуются при каждом изменении;
  • некорректные значения игнорируются вместо частичной обработки.

Типизация и поддержка TypeScript

В современных версиях Tom Select усилилась поддержка TypeScript, что повлияло на API:

  • описаны интерфейсы опций;
  • типизированы события;
  • уточнены возвращаемые значения методов.

Это привело к снижению «динамических» возможностей, характерных для раннего JavaScript-стиля, но повысило предсказуемость интеграции.

Пример типизированной конфигурации:

interface TomSelectOptions {
  maxItems: number;
  create: boolean;
  load(query: string, callback: (options: any[]) => void): void;
}

Поведение DOM и синхронизация

Одно из ключевых улучшений — стабильная синхронизация между:

  • оригинальным <select>;
  • внутренним состоянием;
  • визуальным представлением.

Ранее:

  • DOM мог рассинхронизироваться при кастомных изменениях;
  • требовались ручные refresh() или повторные инициализации.

Теперь:

  • любое изменение проходит через единый слой обновления;
  • UI и state обновляются атомарно;
  • исключены частичные обновления.

Итоговые архитектурные сдвиги API

Эволюция API Tom Select характеризуется переходом к:

  • строгому разделению состояния и UI;
  • предсказуемому жизненному циклу;
  • контролируемым побочным эффектам;
  • унифицированной системе событий;
  • безопасной асинхронности.

Стабилизация интерфейса методов делает поведение компонента менее зависимым от внутренней реализации и упрощает поддержку кода при обновлениях версий.