Haunted — это библиотека для создания веб-компонентов с реактивным состоянием на основе хуков, аналогичных React. Одной из важных задач при работе с состоянием является отслеживание предыдущих значений переменных, что позволяет реализовать сложные реакции на изменения, анимации, сравнение состояний и оптимизацию рендеринга.
useRef для хранения предыдущих значенийВ Haunted ключевым инструментом для хранения данных между рендерами
является useRef. Он возвращает объект с полем
current, которое сохраняет значение между вызовами функции
компонента.
Пример базового использования:
import { html, component, useRef, useEffect } FROM 'haunted';
function Counter() {
const count = useRef(0);
const prevCount = useRef(null);
useEffect(() => {
prevCount.current = count.current;
});
const increment = () => {
count.current += 1;
// Перерендер компонента не происходит автоматически при изменении count.current
};
return html`
<div>
<p>Текущее значение: ${count.current}</p>
<p>Предыдущее значение: ${prevCount.current}</p>
<button @click=${increment}>Увеличить</button>
</div>
`;
}
customElements.define('my-counter', component(Counter));
Особенности:
prevCount.current сохраняет значение, которое было до
последнего изменения.ref.current не вызывает
автоматический ререндер, поэтому для реактивности часто
используют useState совместно с useRef.useState и useRef для отслеживания
измененийДля реактивного отслеживания предыдущих значений удобно комбинировать
useState и useRef:
import { html, component, useState, useRef, useEffect } FROM 'haunted';
function Counter() {
const [count, setCount] = useState(0);
const prevCount = useRef(count);
useEffect(() => {
prevCount.current = count;
}, [count]);
const increment = () => setCount(count + 1);
return html`
<div>
<p>Текущее значение: ${count}</p>
<p>Предыдущее значение: ${prevCount.current}</p>
<button @click=${increment}>Увеличить</button>
</div>
`;
}
customElements.define('my-counter', component(Counter));
Пояснения:
useEffect с зависимостью [count]
выполняется после рендера, что позволяет сохранить предыдущее значение
count до следующего изменения.prevCount.current для
сравнений, условных эффектов и анимаций.usePreviousДля удобства часто создают отдельный хук usePrevious,
который инкапсулирует всю логику хранения предыдущего значения:
import { useRef, useEffect } from 'haunted';
function usePrevious(value) {
const ref = useRef();
useEffect(() => {
ref.current = value;
}, [value]);
return ref.current;
}
Применение в компоненте:
import { html, component, useState } from 'haunted';
import { usePrevious } from './usePrevious.js';
function Counter() {
const [count, setCount] = useState(0);
const prevCount = usePrevious(count);
return html`
<div>
<p>Текущее значение: ${count}</p>
<p>Предыдущее значение: ${prevCount}</p>
<button @click=${() => setCount(count + 1)}>Увеличить</button>
</div>
`;
}
customElements.define('my-counter', component(Counter));
Преимущества подхода:
Иногда требуется хранить не только одно предыдущее значение, но и несколько:
import { useRef, useEffect } from 'haunted';
function useHistory(value, LIMIT = 5) {
const history = useRef([]);
useEffect(() => {
history.current.push(value);
if (history.current.length > LIMIT) {
history.current.shift();
}
}, [value]);
return history.current;
}
Пример использования:
import { html, component, useState } from 'haunted';
import { useHistory } from './useHistory.js';
function Counter() {
const [count, setCount] = useState(0);
const history = useHistory(count, 3);
return html`
<div>
<p>История: ${history.join(', ')}</p>
<button @click=${() => setCount(count + 1)}>Увеличить</button>
</div>
`;
}
customElements.define('my-counter', component(Counter));
Особенности:
useRef вместо
useState для данных, не влияющих на рендер, чтобы
избежать лишних обновлений.useEffect для
выполнения действий после изменения значения.Хранение предыдущих значений в Haunted позволяет строить гибкую
реактивную архитектуру, отслеживать изменения состояния и оптимизировать
работу компонентов. Комбинация useRef,
useState и useEffect обеспечивает
универсальный и мощный подход к управлению историей значений.