Haunted — это библиотека для создания веб-компонентов с использованием реактивного подхода, вдохновлённого React, но построенного на стандарте Web Components. Важнейшей частью построения компонентов в Haunted является управление состоянием. Состояние может быть объектом или примитивом, и понимание различий между ними критично для правильного обновления интерфейса.
Примитивные значения в JavaScript включают string,
number, boolean, null и
undefined. В Haunted их использование очень похоже на
работу с обычными реактивными переменными в других фреймворках.
import { component, html, useState } 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));
Особенности состояния-примитива:
setCount(newValue) сразу триггерит ререндер
компонента.useState и обновляет DOM.Ключевой момент — нельзя мутировать примитив напрямую. Например,
count++ не вызовет перерисовку, если не использовать
setCount.
С объектами ситуация более сложная. В JavaScript объекты и массивы передаются по ссылке, поэтому простое изменение поля объекта не всегда приводит к обновлению компонента.
function UserProfile() {
const [user, setUser] = useState({ name: 'Алексей', age: 30 });
const incrementAge = () => {
setUser({ ...user, age: user.age + 1 });
};
return html`
<div>
<p>Имя: ${user.name}</p>
<p>Возраст: ${user.age}</p>
<button @click=${incrementAge}>Добавить год</button>
</div>
`;
}
customElements.define('user-profile', component(UserProfile));
Особенности состояния-объекта:
user.age++ не вызовет ререндер.
Требуется создавать новый объект с обновлёнными полями
({ ...user, age: user.age + 1 }).Массивы в Haunted работают аналогично объектам. Любые изменения, которые не создают новый массив, не вызовут ререндер:
function TodoList() {
const [todos, setTodos] = useState(['Купить молоко', 'Прочитать книгу']);
const addTodo = () => {
setTodos([...todos, 'Новая задача']);
};
return html`
<ul>
${todos.map(todo => html`<li>${todo}</li>`)}
</ul>
<button @click=${addTodo}>Добавить задачу</button>
`;
}
customElements.define('todo-list', component(TodoList));
Принципы работы с массивами:
push, pop,
splice не триггерит ререндер.slice
гарантирует обновление интерфейса.| Характеристика | Примитив | Объект / Массив |
|---|---|---|
| Обновление состояния | Простое (setValue) |
Только через новый объект/массив |
| Автоматическая реактивность | Полная | Только верхний уровень |
| Хранение нескольких значений | Неподходяще | Подходит для комплексных структур |
| Мутирование | Невозможно без set |
Прямое изменение не срабатывает |
useState
и обновление состоянияuseState в Haunted возвращает массив из двух элементов:
текущее значение и функцию для его обновления. Важно помнить:
setState запускает повторный
рендер текущего компонента.setState, чтобы получить
актуальное значение, что особенно полезно при работе с объектами или
массивами:setUser(prev => ({ ...prev, age: prev.age + 1 }));
Такой подход предотвращает ошибки, связанные с асинхронными обновлениями состояния.
Состояние-примитив и состояние-объект в Haunted создают фундамент для реактивного поведения веб-компонентов. Понимание их особенностей позволяет строить интерфейсы, которые правильно реагируют на изменения данных без лишнего кода и сложных обходных решений.