Библиотека Page.js — это небольшой клиентский роутер для одностраничных приложений на JavaScript, который обеспечивает управление URL и обработку маршрутов без перезагрузки страницы. Одним из ключевых аспектов построения SPA является корректная очистка состояния между переходами по маршрутам, чтобы не возникало конфликтов данных и утечек памяти.
При переходе между маршрутами важно учитывать следующие элементы состояния:
Page.js поддерживает концепцию middleware, что позволяет централизованно обрабатывать очистку перед переходом на новый маршрут. Пример:
function clearState(ctx, next) {
if (window.currentComponent && typeof window.currentComponent.destroy === 'function') {
window.currentComponent.destroy();
}
next();
}
page('*', clearState);
Здесь clearState вызывается перед каждым маршрутом
('*'), проверяет наличие текущего компонента и вызывает его
метод destroy(). Метод destroy должен
содержать логику очистки: удаление DOM-элементов, отмену подписок и
остановку таймеров.
Если SPA активно использует динамическую вставку HTML, важно удалять старые элементы перед рендером новых:
function renderComponent(container, component) {
container.innerHTML = '';
container.appendChild(component.element);
window.currentComponent = component;
}
Метод innerHTML = '' полностью очищает контейнер,
предотвращая накопление устаревших элементов. Хранение ссылки на текущий
компонент через window.currentComponent позволяет вызвать
его destroy при следующей навигации.
Частой проблемой является оставление слушателей событий и таймеров. Их необходимо удалять:
class MyComponent {
constructor() {
this.handleClick = this.handleClick.bind(this);
document.addEventListener('click', this.handleClick);
this.timer = setInterval(this.update.bind(this), 1000);
this.element = document.createElement('div');
}
handleClick(event) {
console.log('Clicked', event.target);
}
update() {
console.log('Updating...');
}
destroy() {
document.removeEventListener('click', this.handleClick);
clearInterval(this.timer);
this.element.remove();
}
}
Вызов destroy() при переходе по маршруту гарантирует,
что ни один старый обработчик или таймер не останется активным.
При работе с формами и данными состояния важно сбрасывать значения:
function clearForm(formElement) {
formElement.reset();
}
function clearAppState() {
window.appState = {};
}
Middleware можно комбинировать с рендерингом, чтобы гарантировать, что перед отображением нового маршрута старые данные сбрасываются:
page('/profile', clearState, (ctx) => {
renderComponent(document.body, new ProfileComponent());
});
Эффективная стратегия очистки состояния — использование единого контейнера для рендеринга текущего компонента. Это упрощает:
container.innerHTML = '').window.currentComponent).destroy.Если компонент использует fetch-запросы или промисы, их нужно контролировать и отменять при смене маршрута:
class AsyncComponent {
constructor() {
this.controller = new AbortController();
this.fetchData();
this.element = document.createElement('div');
}
async fetchData() {
try {
const response = await fetch('/api/data', { signal: this.controller.signal });
this.element.textContent = await response.text();
} catch (err) {
if (err.name === 'AbortError') console.log('Fetch aborted');
}
}
destroy() {
this.controller.abort();
this.element.remove();
}
}
Использование AbortController позволяет безопасно
прерывать запросы при навигации, не оставляя “висячих” промисов.
Если приложение использует глобальные состояния (например, через
объект window.appState или Redux-подобные хранилища), нужно
определять чёткую политику очистки:
Эти подходы обеспечивают предсказуемое поведение приложения, снижение утечек памяти и отсутствие конфликтов между состояниями разных маршрутов в SPA с использованием Page.js.