Событие afterChange

Событие afterChange в Slim Select представляет собой один из ключевых механизмов реакции на изменение состояния выбора. Оно вызывается после того, как пользователь изменил выбранные значения, и компонент завершил внутреннее обновление состояния. В отличие от более ранних хуков жизненного цикла, afterChange отражает уже финализированное состояние селекта, что делает его удобным для синхронизации данных, отправки запросов и построения реактивной логики.

Внутренняя модель работы Slim Select строится вокруг последовательности событий, которые фиксируют разные этапы взаимодействия пользователя с элементом выбора. afterChange вызывается последним в цепочке изменений выбора.

Типичная последовательность выглядит следующим образом:

  • пользователь инициирует изменение (клик по опции, ввод поиска, программное изменение)
  • выполняется предварительная обработка состояния
  • обновляется модель выбранных значений
  • обновляется DOM
  • вызываются промежуточные события (если они предусмотрены)
  • вызывается afterChange

Ключевой момент заключается в том, что к моменту вызова afterChange:

  • DOM уже синхронизирован с состоянием
  • внутренний массив выбранных значений актуален
  • все вычисления фильтрации и поиска завершены

Это делает afterChange стабильной точкой для чтения состояния без риска получить промежуточные данные.

Сигнатура и структура данных события

В Slim Select afterChange обычно передаёт массив объектов, описывающих текущее состояние выбора.

Общий формат:

select.on('afterChange', (info) => {
  console.log(info);
});

Где info представляет собой массив элементов следующей структуры:

[
  {
    text: "Название опции",
    value: "значение",
    selected: true
  }
]

Если режим множественного выбора включён, массив содержит несколько объектов. В режиме одиночного выбора массив содержит один элемент либо становится пустым при очистке выбора.

Поведение при различных режимах работы

Одиночный выбор

В режиме single select afterChange отражает текущее выбранное значение или пустое состояние.

Пример:

const select = new SlimSelect({
  select: '#single'
});

select.on('afterChange', (data) => {
  const value = data.length ? data[0].value : null;
  console.log('Выбрано:', value);
});

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

Множественный выбор

В multi-select режиме afterChange становится агрегатором состояния:

select.on('afterChange', (data) => {
  const values = data.map(item => item.value);
  console.log(values);
});

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

Отличие afterChange от beforeChange и change

В экосистеме Slim Select часто сравнивают несколько событий:

  • beforeChange — вызывается до применения изменений
  • change — более общее событие изменения DOM-элемента
  • afterChange — вызывается после завершения всех внутренних обновлений

Ключевое отличие afterChange заключается в гарантированной консистентности состояния. В момент его вызова:

  • значения уже записаны в оригинальный <select>
  • виртуальная модель синхронизирована
  • UI обновлён

В отличие от beforeChange, где возможна отмена или модификация операции, afterChange используется только для наблюдения.

Типичные сценарии использования

Синхронизация с сервером

afterChange часто применяется для немедленной отправки фильтров:

select.on('afterChange', (data) => {
  const filters = data.map(i => i.value);

  fetch('/api/items', {
    method: 'POST',
    body: JSON.stringify({ filters })
  });
});

Такой подход особенно характерен для интерфейсов с динамической фильтрацией.

Обновление UI

Изменение других компонентов интерфейса на основе выбранных значений:

select.on('afterChange', (data) => {
  document.querySelector('#count').textContent = data.length;
});

Каскадные селекты

afterChange активно используется при построении зависимых списков:

parentSelect.on('afterChange', (data) => {
  const parentValue = data[0]?.value;

  loadChildOptions(parentValue);
});

Особенности повторных вызовов

В Slim Select важно учитывать, что afterChange может вызываться не только в ответ на действия пользователя, но и при программных изменениях:

select.set(['value1', 'value2']);

Это приводит к вызову afterChange, что иногда вызывает каскадные эффекты, если внутри обработчика выполняются новые изменения состояния.

Для предотвращения циклических вызовов используется флаг блокировки:

let isUpdating = false;

select.on('afterChange', (data) => {
  if (isUpdating) return;

  isUpdating = true;
  updateSomething(data);
  isUpdating = false;
});

Производительность при больших списках

При работе с тысячами элементов afterChange может становиться узким местом, если внутри обработчика выполняются тяжёлые операции.

Основные источники нагрузки:

  • полная пересборка массива выбранных значений
  • частые вызовы при быстром изменении выбора
  • синхронные DOM-операции внутри обработчика

Оптимизационный подход:

  • минимизация логики внутри afterChange
  • использование debounce при сетевых запросах
  • кэширование результатов преобразования данных

Пример debounce:

let timeout;

select.on('afterChange', (data) => {
  clearTimeout(timeout);

  timeout = setTimeout(() => {
    sendToServer(data);
  }, 300);
});

Работа с асинхронными операциями

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

Важно учитывать порядок выполнения:

  • afterChange вызывается синхронно
  • асинхронные операции внутри него не блокируют UI
  • возможны гонки состояния при быстрых изменениях

Пример безопасной обработки:

let requestId = 0;

select.on('afterChange', async (data) => {
  const currentRequest = ++requestId;

  const result = await fetchData(data);

  if (currentRequest !== requestId) return;

  render(result);
});

Взаимодействие с программным API

Slim Select позволяет управлять состоянием программно через методы API, и afterChange всегда отражает результат таких операций.

Методы, вызывающие afterChange:

  • set()
  • add()
  • remove()
  • setData() (в зависимости от конфигурации)

Пример:

select.set(['a', 'b']);

После выполнения этого вызова afterChange получает обновлённый массив выбранных значений.

Предсказуемость и детерминированность

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

Это позволяет:

  • строить чистые функции обработки состояния
  • выносить логику в отдельные модули
  • использовать функциональный подход

Пример чистой обработки:

function extractValues(data) {
  return data.map(item => item.value);
}

select.on('afterChange', (data) => {
  const values = extractValues(data);
  updateState(values);
});

Ошибки при работе с afterChange

На практике часто встречаются следующие ошибки:

  1. Дублирование логики между change и afterChange
  2. Изменение состояния внутри обработчика без защиты от рекурсии
  3. Выполнение тяжёлых вычислений без оптимизации
  4. Предположение, что событие вызывается только пользователем

Корректная архитектура предполагает, что afterChange используется как финальная точка синхронизации состояния, без побочных эффектов, влияющих на сам select.

Роль afterChange в архитектуре интерфейса

В сложных интерфейсах Slim Select afterChange становится связующим звеном между UI и бизнес-логикой. Он выполняет роль стабилизатора состояния, обеспечивая единый источник истины для выбранных данных.

При правильной организации логики:

  • Slim Select отвечает только за UI и выбор
  • afterChange передаёт состояние наружу
  • внешняя система управляет данными и эффектами

Такая схема снижает связанность компонентов и упрощает масштабирование интерфейса.