Библиотеки для форм

Haunted — это минималистичная библиотека для создания веб-компонентов на основе Web Components и Hooks, вдохновлённая React. Основная идея заключается в том, чтобы объединить легковесность Web Components с удобством реактивного управления состоянием через хуки.

Библиотека предоставляет возможность создавать функциональные компоненты, управлять состоянием с помощью useState, выполнять побочные эффекты через useEffect и работать с жизненным циклом компонента, не отходя от стандартов браузера.

Установка и подключение

Haunted можно подключить через npm:

npm install haunted

Или использовать CDN для быстрого прототипирования:

<script type="module">
  import { html, component, useState, useEffect } from 'https://unpkg.com/haunted/haunted.js?module';
</script>

Ключевые экспорты:

  • html — функция-шаблонизатор, аналог JSX, но на чистых шаблонных литералах.
  • component — функция для регистрации веб-компонента.
  • useState, useEffect, useReducer, useRef, useContext — хуки для управления состоянием и жизненным циклом.

Создание компонента

Простейший функциональный компонент выглядит так:

import { html, component } from 'haunted';

function Counter() {
  const [count, setCount] = useState(0);
  
  return html`
    <div>
      <p>Счётчик: ${count}</p>
      <button @click=${() => setCount(count + 1)}>Увеличить</button>
    </div>
  `;
}

customElements.define('my-counter', component(Counter));

Особенности:

  • Использование шаблонных литералов через html.
  • Хук useState создаёт реактивное состояние, при изменении которого компонент перерисовывается.
  • Обработчики событий можно привязывать через @событие=${функция}.

Хуки в Haunted

useState

useState(initialValue) возвращает массив [state, setState], аналогичный React. Изменение state вызывает повторный рендер компонента.

useEffect

useEffect(callback, dependencies) позволяет выполнять побочные эффекты. Если dependencies опущены, эффект выполняется после каждого рендера. Если передан массив зависимостей, эффект выполняется только при их изменении.

useEffect(() => {
  console.log('Компонент обновлён');
}, [count]);

useReducer

Альтернатива useState для сложной логики обновления состояния:

const [state, dispatch] = useReducer((state, action) => {
  switch(action.type) {
    case 'increment': return state + 1;
    default: return state;
  }
}, 0);

useRef

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

const inputRef = useRef();
html`<input type="text" ${ref(inputRef)} />`

Взаимодействие с формами

Haunted прекрасно подходит для управления формами благодаря реактивному состоянию. Пример формы с полями и валидацией:

function LoginForm() {
  const [form, setForm] = useState({ username: '', password: '' });
  const [error, setError] = useState('');

  const handleSubmit = (e) => {
    e.preventDefault();
    if (!form.username || !form.password) {
      setError('Все поля обязательны');
      return;
    }
    console.log('Форма отправлена', form);
  };

  return html`
    <form @submit=${handleSubmit}>
      <label>
        Логин:
        <input type="text" .value=${form.username} @input=${e => setForm({ ...form, username: e.target.value })} />
      </label>
      <label>
        Пароль:
        <input type="password" .value=${form.password} @input=${e => setForm({ ...form, password: e.target.value })} />
      </label>
      ${error && html`<p style="color:red;">${error}</p>`}
      <button type="submit">Войти</button>
    </form>
  `;
}

customElements.define('login-form', component(LoginForm));

Ключевые моменты при работе с формами:

  • Использование .value вместо value для привязки состояния.
  • Обработчики @input позволяют синхронизировать состояние с полями.
  • Состояние формы хранится централизованно в useState, что упрощает валидацию и обработку данных.

Контекст и совместное состояние

Haunted поддерживает Context для передачи данных между компонентами без проброса через пропсы:

import { createContext, useContext } from 'haunted';

const UserContext = createContext();

function Profile() {
  const user = useContext(UserContext);
  return html`<p>Пользователь: ${user.name}</p>`;
}

function App() {
  return html`
    <${UserContext.Provider} value=${{ name: 'Иван' }}>
      <profile></profile>
    <//>
  `;
}

Это особенно удобно для больших приложений с множеством форм и компонентами, которым требуется доступ к общему состоянию.

Интеграция с другими библиотеками

Haunted легко интегрируется с библиотеками для форм, такими как Formik или Yup, благодаря независимости от фреймворка. Основная идея — хранить состояние формы в useState или useReducer, а валидацию выполнять через сторонние библиотеки внутри useEffect или обработчиков событий.

Производительность и оптимизация

  • Haunted минимизирует лишние рендеры за счёт хуков и реактивного состояния.
  • Использование шаблонных литералов позволяет обновлять только изменившиеся части DOM.
  • Рекомендуется разбивать большие формы на отдельные компоненты для уменьшения нагрузки на рендер.

Примеры расширенных форм

Формы с динамическими полями и списками:

function TodoForm() {
  const [todos, setTodos] = useState([{ text: '' }]);

  const addTodo = () => setTodos([...todos, { text: '' }]);
  const updateTodo = (index, value) => {
    const newTodos = [...todos];
    newTodos[index].text = value;
    setTodos(newTodos);
  };

  return html`
    <div>
      ${todos.map((todo, i) => html`
        <input type="text" .value=${todo.text} @input=${e => updateTodo(i, e.target.value)} />
      `)}
      <button @click=${addTodo}>Добавить</button>
    </div>
  `;
}

customElements.define('todo-form', component(TodoForm));

Особенности:

  • Реактивное обновление списка через useState.
  • Возможность динамического добавления и редактирования полей без полной перерисовки компонента.

Haunted сочетает в себе легковесность Web Components, удобство хуков и возможности управления сложными формами, делая разработку современных реактивных интерфейсов максимально гибкой и производительной.