Lifecycle методы

Инициализация состояния и подключение Kepler.gl к приложению

Kepler.gl строится вокруг Redux-архитектуры и React-компонентов, поэтому жизненный цикл начинается не внутри самой библиотеки, а на уровне интеграции контейнера KeplerGl. Первичный этап — создание Redux-store с подключением редьюсера Kepler:

import keplerGlReducer from 'kepler.gl/reducers';

const store = createStore(
  combineReducers({
    keplerGl: keplerGlReducer
  }),
  {},
  applyMiddleware(...)
);

На этом уровне формируется базовая структура состояния: visState, mapState, uiState. Уже здесь определяется фундамент жизненного цикла визуализации — любые дальнейшие изменения проходят через dispatch-цепочку.

Ключевой момент: Kepler.gl не управляет состоянием напрямую, он реагирует на изменения Redux-store, что делает lifecycle предсказуемым и детерминированным.


Монтирование компонента KeplerGl

При первом рендере React-компонента KeplerGl запускается стандартный lifecycle React:

  • constructor
  • render
  • componentDidMount

Именно componentDidMount становится точкой инициализации карты и WebGL-контекста.

Внутри KeplerGl происходит:

  1. Создание контейнера Mapbox / deck.gl
  2. Инициализация WebGL canvas
  3. Подключение взаимодействий (pan, zoom, rotate)
  4. Привязка Redux-состояния к визуализации

Пример использования:

<KeplerGl
  id="map"
  width={width}
  height={height}
  mapboxApiAccessToken={token}
/>

После монтирования компонент диспатчит внутренние экшены:

  • INIT — создание инстанса карты
  • ADD_DATA_TO_MAP — загрузка стартовых данных (если переданы)
  • LAYER_CONFIG_CHANGE — применение конфигурации слоёв

На этом этапе формируется первая визуальная сцена.


Жизненный цикл загрузки данных

Одним из ключевых lifecycle-процессов является добавление данных в карту. Это не просто загрузка массива, а многоступенчатый процесс трансформации:

dispatch(addDataToMap({
  datasets: {
    info: { label: 'Data' },
    data: rawData
  },
  options: {
    centerMap: true,
    readOnly: false
  }
}));

После dispatch происходит цепочка событий:

  1. Парсинг данных

    • определение типов колонок
    • вычисление агрегатов
    • подготовка индексов
  2. Обновление visState

    • создание dataset entry
    • инициализация layers
    • расчет filter domain
  3. Пересборка визуализации

    • deck.gl layers re-initialization
    • пересчёт viewport

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


componentDidUpdate и реактивное обновление

При изменении props у KeplerGl запускается componentDidUpdate. Это один из наиболее важных lifecycle-этапов, так как Kepler.gl реагирует на внешние изменения:

  • обновление datasets
  • изменение темы
  • смена конфигурации карты
  • изменение viewport

Внутренний механизм сравнивает предыдущие и новые props:

componentDidUpdate(prevProps) {
  if (prevProps.datasets !== this.props.datasets) {
    dispatch(addDataToMap(...));
  }

  if (prevProps.config !== this.props.config) {
    dispatch(loadConfig(this.props.config));
  }
}

Типы реакций системы

1. Изменение данных

  • пересборка layers
  • обновление фильтров
  • перерасчёт агрегатов

2. Изменение конфигурации

  • восстановление UI состояния
  • применение layout слоёв
  • синхронизация interaction state

3. Изменение viewport

  • обновление камеры
  • синхронизация mapState
  • перерасчёт bounding box

shouldComponentUpdate и оптимизация рендера

Kepler.gl активно использует оптимизации, связанные с предотвращением лишних перерисовок. shouldComponentUpdate контролирует, когда компонент должен реагировать на изменения.

Типичная логика:

  • сравнение id контейнера
  • проверка изменения dataset hash
  • анализ изменения mapState
  • проверка UI state

Если изменения не затрагивают визуализацию, повторный render блокируется.

Это критично для больших наборов данных, где повторный рендер WebGL сцены может стоить десятки миллисекунд.


Внутренний lifecycle Redux: actions → reducers → state

Kepler.gl имеет собственный «скрытый lifecycle», который полностью построен на Redux-потоке.

Основные стадии:

Dispatch action

dispatch(updateMap(viewState));

Reducer processing

  • keplerGlReducer получает action
  • определяет целевую ветку состояния
  • применяет изменения immutably

State propagation

  • React получает новый props
  • KeplerGl обновляет визуализацию

Ключевые редьюсеры:

  • visState — слои, фильтры, данные
  • mapState — камера и viewport
  • uiState — интерфейс и панели

Каждый из них имеет собственный жизненный цикл обновления.


Lifecycle слоёв (layers lifecycle)

Отдельный важный цикл — жизненный цикл слоёв карты.

Создание слоя

Происходит при:

  • добавлении dataset
  • загрузке конфигурации
  • ручном создании слоя
layers.push(new ScatterplotLayer({...}));

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

Trigger события:

  • изменение фильтра
  • изменение цвета
  • изменение данных

Каждое обновление вызывает:

  • updateState
  • перерасчёт позиции точек
  • пересоздание instance attributes

Удаление слоя

  • удаление из visState
  • очистка GPU ресурсов
  • удаление из deck.gl tree

Lifecycle viewport (mapState)

Viewport — отдельный объект жизненного цикла, связанный с камерой.

Основные события:

  • zoom change
  • pan
  • bearing update
  • pitch change

Каждое изменение вызывает action:

dispatch(updateMapState({
  latitude,
  longitude,
  zoom
}));

Далее происходит синхронизация:

  • deck.gl camera update
  • mapbox sync (если используется base map)
  • recalculation of visible bounds

Lifecycle взаимодействий (interactions)

Kepler.gl управляет взаимодействиями через interactionState:

  • drag selection
  • hover events
  • tooltip rendering
  • brushing filters

Каждое взаимодействие проходит цикл:

  1. событие UI (mouse/keyboard)
  2. dispatch interaction action
  3. обновление interactionState
  4. rerender overlay layers

componentWillUnmount и очистка ресурсов

При удалении компонента запускается завершающий lifecycle:

  • componentWillUnmount

Внутренние процессы:

  1. Удаление WebGL контекста
  2. Очистка deck.gl layers
  3. Отписка от Redux listeners
  4. Очистка event listeners (mouse, resize)
  5. Освобождение памяти от dataset references

Особенно критичен этап очистки GPU ресурсов, так как утечки WebGL-контекста приводят к деградации производительности при повторном монтировании.


Асинхронный lifecycle рендеринга карты

Несмотря на Redux-синхронность, визуализация в Kepler.gl имеет асинхронную природу:

  • данные могут загружаться частями
  • слои пересчитываются батчами
  • WebGL обновляет сцену через requestAnimationFrame

Типичный цикл:

  1. Redux update
  2. React render
  3. deck.gl reconciliation
  4. GPU draw call
  5. frame presentation

Этот pipeline делает lifecycle многослойным: состояние, UI и графика живут в разных временных шкалах.


Lifecycle конфигурации (configState)

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

  • загрузка saved config
  • merge с текущим state
  • применение layer styles
  • восстановление UI layout
dispatch(loadConfig(config));

При этом происходит строгая синхронизация:

  • layers mapping
  • filter state restore
  • interaction state alignment
  • viewport restore

Несоответствие конфигурации и данных приводит к частичной деградации визуализации (например, слои без источника данных).


Событийная модель как продолжение lifecycle

Kepler.gl можно рассматривать как систему событий, где lifecycle выражается через поток:

  • INIT
  • LOAD_DATA
  • UPDATE_VISUALIZATION
  • INTERACTION
  • UPDATE_VIEW
  • CLEANUP

Каждое событие не является изолированным — оно всегда порождает каскад обновлений внутри Redux-store и WebGL сцены, формируя непрерывный цикл синхронизации состояния и визуализации.