Отладка хуков

Haunted — это библиотека для создания веб-компонентов с использованием реактивных хуков, аналогичных React. Отладка хуков требует понимания их жизненного цикла и особенностей работы с состоянием, эффектами и мемоизацией.

Особенности жизненного цикла хуков

Хуки в Haunted работают строго внутри функционального компонента. Любое нарушение правил их использования приводит к непредсказуемому поведению:

  • Хуки должны вызываться только на верхнем уровне компонента. Вызов внутри условных операторов или циклов ломает последовательность и может привести к ошибкам при повторном рендере.
  • Порядок вызова хуков должен оставаться неизменным между рендерами. Изменение порядка приводит к неправильной привязке состояния и эффектов.

Отладка часто начинается с проверки этих правил. Простой способ — использовать строгий режим и проверять консоль на предупреждения.

Отслеживание состояния с useState

useState — основной инструмент хранения локального состояния. Ошибки обычно связаны с неинициализированным состоянием или неправильной структурой обновления:

import { html, useState } from 'haunted';

function Counter() {
  const [count, setCount] = useState(0);

  return html`<button @click=${() => setCount(count + 1)}>
    Счётчик: ${count}
  </button>`;
}
  • Для отладки важно проверять текущее состояние при каждом рендере. Использование console.log(count) внутри компонента поможет выявить неожиданные изменения.
  • При работе с объектами или массивами нужно создавать новые копии при обновлении, чтобы Haunted корректно отслеживал изменения.

Управление побочными эффектами с useEffect

useEffect выполняется после рендера и позволяет управлять побочными эффектами. Ошибки часто проявляются в неправильной зависимости:

import { html, useEffect, useState } from 'haunted';

function Timer() {
  const [seconds, setSeconds] = useState(0);

  useEffect(() => {
    const id = setInterval(() => setSeconds(s => s + 1), 1000);
    return () => clearInterval(id);
  }, []);
  
  return html`<p>Время: ${seconds}</p>`;
}
  • Для отладки важно проверять массив зависимостей. Пропуск значений или лишние зависимости могут вызвать бесконечные циклы рендеров.
  • Использование console.log внутри эффекта позволяет убедиться, что эффект вызывается ожидаемое количество раз.

Меморизация значений с useMemo и useCallback

useMemo и useCallback применяются для оптимизации и предотвращения лишних пересчётов:

import { html, useMemo, useState } from 'haunted';

function Expensive({ num }) {
  const result = useMemo(() => {
    let sum = 0;
    for (let i = 0; i < 1000000; i++) sum += num;
    return sum;
  }, [num]);

  return html`<p>Результат: ${result}</p>`;
}
  • Отладка требует проверки, что зависимости действительно изменяются только тогда, когда это необходимо.
  • Неверное указание зависимостей приводит к устаревшим или некорректным результатам вычислений.

Пользовательские хуки

Haunted позволяет создавать собственные хуки, которые возвращают состояние, эффекты или функции:

import { useState, useEffect } from 'haunted';

function useCounter(initial = 0) {
  const [count, setCount] = useState(initial);

  useEffect(() => {
    console.log(`Счётчик обновлён: ${count}`);
  }, [count]);

  return [count, setCount];
}
  • Основная трудность при отладке пользовательских хуков — соблюдение правил вызова хуков внутри них.
  • Важная практика — добавление логирования на каждом уровне, чтобы отслеживать цепочку вызовов и состояние.

Инструменты для отладки

  • Консоль браузера: вывод состояния и сообщений о вызовах эффектов.
  • Строгий режим Haunted: включает дополнительные проверки и предупреждения о неправильном использовании хуков.
  • Разделение компонентов: мелкие компоненты с минимальным числом хуков упрощают локализацию ошибок.
  • Тестирование эффектов: использование Jest или других фреймворков для имитации рендера и проверки вызовов хуков.

Отслеживание ререндеров

В Haunted каждый вызов компонента может приводить к ререндеру. Для отладки полезно:

  • Добавлять console.log в тело компонента.
  • Проверять, какие хуки вызываются повторно.
  • Следить за состояниями, которые инициируют ререндер, чтобы избежать бесконечных циклов.

Частые ошибки и способы их выявления

  1. Нарушение правил вызова хуков: вызов внутри условий или циклов. Выявляется через консольные предупреждения.
  2. Неправильные зависимости useEffect или useMemo: вызывает лишние рендеры или устаревшие данные. Решение — строгий анализ зависимостей.
  3. Мутация состояния: изменение объекта или массива без создания новой копии. Проверяется через логирование состояния до и после обновления.
  4. Отсутствие очистки эффектов: таймеры или подписки продолжают работать после удаления компонента. Отслеживается через return в useEffect.

Практика логирования

  • Каждое обновление состояния: console.log('state updated', state).
  • Каждое выполнение эффекта: console.log('effect run', dependencies).
  • Вызов пользовательских хуков: логирование входных и выходных значений.

Такой подход позволяет локализовать источник ошибки и понять, на каком этапе хуки работают некорректно.