ifDefined и guard

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


ifDefined

ifDefined используется для управления значением атрибутов HTML. Часто в веб-компонентах необходимо установить атрибут только если значение определено. Без этой утилиты при значении undefined или null атрибут всё равно будет присутствовать с пустым значением, что может нарушить логику компонента.

Синтаксис:

import { html } from 'haunted';
import { ifDefined } from 'haunted';

const MyComponent = ({ title }) => html`
  
Контент
`;
  • Если title имеет значение, оно будет установлено как атрибут.
  • Если title равно undefined или null, атрибут не будет добавлен в DOM.

Примеры применения:

  1. Атрибуты форм:
const InputField = ({ placeholder }) => html`
  
`;

Если placeholder не передан, браузер не создаст пустой атрибут, что позволяет избежать визуальных и функциональных ошибок.

  1. Динамические свойства:
const Button = ({ disabled }) => html`
  
`;

В данном случае ifDefined не обязателен при булевых атрибутах, но иногда его удобно использовать при комбинированной логике значений, например, когда атрибут может быть строкой или undefined.

Особенности работы:

  • ifDefined всегда возвращает либо переданное значение, либо специальный маркер nothing, который Haunted понимает как отсутствие атрибута.
  • Позволяет писать более чистый код без лишних проверок перед шаблоном.

guard

guard — это утилита для оптимизации рендеринга сложных шаблонов. Она предотвращает повторный рендеринг части шаблона, если входные данные не изменились. Это особенно полезно при работе с массивами или тяжёлыми вычислениями внутри шаблона.

Синтаксис:

import { html } from 'haunted';
import { guard } from 'haunted';

const List = ({ items }) => html`
  
    ${guard([items], () => html` ${items.map(item => html`
  • ${item}
  • `)} `)}
`;
  • Первый аргумент — массив зависимостей. Если значения не изменились с предыдущего рендера, функция не выполняется повторно.
  • Второй аргумент — функция, возвращающая шаблон.

Примеры применения:

  1. Списки:
const UsersList = ({ users }) => html`
  
    ${guard([users], () => html` ${users.map(user => html`
  • ${user.name}
  • `)} `)}
`;

Если массив users не меняется между рендерами, Haunted пропустит выполнение функции, что повышает производительность.

  1. Кастомные вычисления:
const ExpensiveComponent = ({ data }) => html`
  ${guard([data], () => {
    const processed = data.map(d => expensiveCalculation(d));
    return html`${processed.join(', ')}`;
  })}
`;

Особенности работы:

  • guard сравнивает зависимости по ссылке. Изменение ссылочного типа, даже если содержимое одно и то же, вызовет повторный рендер.
  • Можно использовать для обёртывания отдельных частей шаблона, а не всего компонента, что минимизирует лишние обновления.

Совместное использование ifDefined и guard

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

const Card = ({ title, items }) => html`
  
${guard([items], () => html`
    ${items.map(item => html`
  • ${item}
  • `)}
`)}
`;
  • ifDefined гарантирует корректное отображение атрибутов.
  • guard предотвращает лишний рендер списка при неизменных данных.

Использование этих утилит делает компоненты Haunted более предсказуемыми и производительными, особенно при работе с динамическими данными и сложными шаблонами.