В контексте Universal Router синхронизация с внешним
хранилищем — это процесс, при котором маршрутизатор взаимодействует с
внешними источниками данных для получения или сохранения состояния
маршрутов. Внешние хранилища могут включать локальное хранилище
браузера (localStorage, sessionStorage), IndexedDB, серверные API или
Redux-стор. Основная цель — обеспечить постоянство
состояния навигации и возможность восстановления маршрутов
после перезагрузки страницы или перехода между вкладками.
Ключевые задачи синхронизации:
Для сохранения состояния маршрута чаще всего используется метод обертки над Universal Router, где каждый переход сопровождается сохранением данных во внешнем хранилище.
Пример использования localStorage:
import UniversalRouter from 'universal-router';
const routes = [
{
path: '/',
action: () => 'Главная страница',
},
{
path: '/profile/:id',
action: ({ params }) => `Профиль пользователя ${params.id}`,
}
];
const router = new UniversalRouter(routes);
async function navigate(path) {
const result = await router.resolve(path);
// Сохраняем последний путь
localStorage.setItem('lastRoute', path);
return result;
}
// Восстановление маршрута при загрузке страницы
const lastRoute = localStorage.getItem('lastRoute');
if (lastRoute) {
router.resolve(lastRoute).then(page => {
console.log(page);
});
}
Ключевой момент: синхронизация состояния маршрута позволяет пользователю вернуться к последней посещенной странице без дополнительной логики на сервере.
При использовании глобальных сторов (Redux,
Vuex) можно реализовать реактивное обновление маршрутов на
основе состояния приложения. В этом случае Universal Router не только
читает состояние, но и инициирует
изменения при навигации.
Пример интеграции с Redux:
import { createStore } from 'redux';
import UniversalRouter from 'universal-router';
const initialState = {
currentRoute: '/',
};
function reducer(state = initialState, action) {
switch(action.type) {
case 'NAVIGATE':
return { ...state, currentRoute: action.path };
default:
return state;
}
}
const store = createStore(reducer);
const routes = [
{ path: '/', action: () => 'Главная' },
{ path: '/about', action: () => 'О нас' },
];
const router = new UniversalRouter(routes);
store.subscribe(() => {
const state = store.getState();
router.resolve(state.currentRoute).then(page => console.log(page));
});
function navigate(path) {
store.dispatch({ type: 'NAVIGATE', path });
}
Вывод: синхронизация с глобальным стором позволяет централизованно управлять навигацией и отслеживать изменения маршрутов в реальном времени.
Иногда необходимо сохранять состояние маршрута на сервере, чтобы обеспечить мультиустройственный доступ. В этом случае Universal Router интегрируется с асинхронными API-запросами, при этом разрешение маршрута может зависеть от данных сервера.
Пример:
import UniversalRouter from 'universal-router';
const routes = [
{
path: '/dashboard',
async action() {
const userData = await fetch('/api/user-data').then(res => res.json());
return `Дашборд пользователя ${userData.name}`;
}
}
];
const router = new UniversalRouter(routes);
async function navigate(path) {
const page = await router.resolve(path);
// Отправляем текущий маршрут на сервер
await fetch('/api/save-route', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ path })
});
return page;
}
Особенности:
Universal Router не предоставляет встроенного механизма подписки на изменения маршрутов, но можно реализовать паттерн наблюдателя, позволяющий синхронизировать маршруты с внешним хранилищем.
Пример:
const subscribers = [];
function subscribe(callback) {
subscribers.push(callback);
}
function notify(path) {
subscribers.forEach(cb => cb(path));
}
async function navigate(path) {
const page = await router.resolve(path);
notify(path);
return page;
}
// Использование
subscribe(path => {
localStorage.setItem('currentRoute', path);
});
Преимущество: такой подход обеспечивает гибкость в интеграции с любыми внешними системами и позволяет управлять синхронизацией независимо от конкретного хранилища.
Для синхронизации маршрутов с history API необходимо
учитывать:
pushState для создания нового состояния без
перезагрузки.replaceState для обновления текущего состояния.popstate для реакции на кнопки
«назад» и «вперед».Пример интеграции:
window.addEventListener('popstate', () => {
router.resolve(window.location.pathname);
});
function navigate(path) {
history.pushState({}, '', path);
router.resolve(path);
}
Ключевой момент: синхронизация с историей браузера позволяет сохранить привычное поведение навигации, одновременно обеспечивая реактивность Universal Router.
Эти подходы формируют полноценную стратегию синхронизации Universal Router с внешними хранилищами, обеспечивая сохранность маршрутов, поддержку динамических данных и реактивность навигации в сложных приложениях.