Haunted — это библиотека для создания веб-компонентов с использованием реактивного подхода, вдохновлённого React Hooks. Одной из ключевых концепций, позволяющих создавать интерактивные и отзывчивые интерфейсы, являются оптимистичные обновления. Эта техника помогает улучшить пользовательский опыт, минимизируя задержку между действием пользователя и визуальным откликом интерфейса.
Оптимистичное обновление предполагает, что состояние изменяется локально сразу, даже до того, как сервер подтвердит успешное выполнение операции. Такой подход уменьшает ощущение “задержки” и делает интерфейс более отзывчивым.
В Haunted оптимистичные обновления тесно связаны с Hook
useState и асинхронными эффектами через
useEffect.
Пример базовой структуры:
import { component, useState, html } from 'haunted';
function LikeButton({ initialLikes = 0 }) {
const [likes, setLikes] = useState(initialLikes);
const handleLike = async () => {
// Оптимистичное обновление
setLikes(likes + 1);
try {
await fetch('/api/like', { method: 'POST' });
} catch (error) {
// Откат при ошибке
setLikes(likes);
console.error('Ошибка при обновлении лайка:', error);
}
};
return html`
<button @click=${handleLike}>❤️ ${likes}</button>
`;
}
customElements.define('like-button', component(LikeButton));
Ключевые моменты:
setLikes(likes + 1) выполняется сразу,
отображая новый результат.Оптимистичные обновления особенно эффективны при работе с асинхронными запросами. Haunted позволяет сочетать локальное состояние и асинхронные операции без сложного управления событиями.
Пример использования useState с
useEffect:
import { component, useState, useEffect, html } from 'haunted';
function TodoItem({ todo }) {
const [completed, setCompleted] = useState(todo.completed);
const toggleComplete = async () => {
setCompleted(!completed); // оптимистичное обновление
try {
await fetch(`/api/todos/${todo.id}`, {
method: 'PATCH',
body: JSON.stringify({ completed: !completed }),
headers: { 'Content-Type': 'application/json' }
});
} catch (error) {
setCompleted(completed); // откат
console.error('Не удалось обновить задачу', error);
}
};
return html`
<label>
<input type="checkbox" .checked=${completed} @change=${toggleComplete} />
${todo.text}
</label>
`;
}
customElements.define('todo-item', component(TodoItem));
Особенности:
completed обновляется мгновенно при
клике.При работе с несколькими элементами, обновление состояния должно учитывать текущее значение, чтобы избежать коллизий. В Haunted для этого можно использовать функцию обновления состояния:
const addItem = async (newItem) => {
setItems(items => [...items, newItem]); // оптимистичное добавление
try {
await fetch('/api/items', {
method: 'POST',
body: JSON.stringify(newItem),
headers: { 'Content-Type': 'application/json' }
});
} catch (error) {
setItems(items => items.filter(item => item !== newItem)); // откат
}
};
Преимущества:
setItems гарантирует, что обновление
использует актуальное состояние.Haunted предоставляет возможность использования
контекста для глобального состояния через
createContext. Оптимистичные обновления в таком случае
позволяют синхронизировать локальные действия с глобальным состоянием
приложения.
Пример:
import { createContext, useContext } from 'haunted';
const CartContext = createContext();
function CartProvider({ children }) {
const [cart, setCart] = useState([]);
const addToCart = async (item) => {
setCart(cart => [...cart, item]); // оптимистичное обновление
try {
await fetch('/api/cart', { method: 'POST', body: JSON.stringify(item) });
} catch (error) {
setCart(cart => cart.filter(i => i !== item)); // откат при ошибке
}
};
return html`<cart-context .value=${{ cart, addToCart }}>${children}</cart-context>`;
}
Преимущества использования контекста:
Оптимистичные обновления в Haunted позволяют создавать интерфейсы с
мгновенной отзывчивостью, сохраняя при этом корректность данных через
откаты при ошибках. Комбинация useState, асинхронных
функций и контекста делает паттерн мощным инструментом для построения
интерактивных веб-компонентов.
Оптимистичный подход особенно полезен в списках, корзинах, лайках и любых действиях, где мгновенный отклик повышает качество пользовательского опыта.