Zustand и маршрутизация

Zustand — это минималистичная библиотека для управления состоянием в приложениях на React. Она отлично сочетается с современными инструментами маршрутизации, такими как React Router, позволяя создавать гибкую архитектуру с локальным и глобальным состоянием компонентов.


Основы Zustand

Zustand использует функцию create для определения глобального состояния. Пример базового хранилища:

import { create } from 'zustand';

const useStore = create((set) => ({
  user: null,
  setUser: (user) => set({ user }),
  logout: () => set({ user: null }),
}));
  • user — текущее состояние пользователя.
  • setUser — метод для обновления состояния.
  • logout — метод для очистки состояния.

Особенности Zustand:

  • Простота API, без необходимости использовать провайдеры.
  • Поддержка функций и селекторов для оптимизации перерисовки компонентов.
  • Возможность комбинировать локальное и глобальное состояние без лишней сложности.

Интеграция с React Router

React Router предоставляет средства для организации маршрутов в приложении. Основные компоненты:

  • — обёртка для работы с HTML5 History API.
  • и — декларативное описание маршрутов.
  • — программная навигация.
  • useNavigate, useParams, useLocation — хуки для работы с навигацией и параметрами.

Пример базовой структуры маршрутов:

import { BrowserRouter, Routes, Route } from 'react-router-dom';
import Home from './Home';
import Profile from './Profile';

function App() {
  return (
    
      
        } />
        } />
      
    
  );
}

Состояние и маршрутизация вместе

Zustand позволяет хранить состояние, которое может влиять на маршрутизацию или реагировать на изменения URL.

Пример: ограниченный доступ к страницам на основе состояния пользователя

import { useStore } from './store';
import { Navigate } from 'react-router-dom';

function ProtectedRoute({ children }) {
  const user = useStore((state) => state.user);
  return user ? children : ;
}

Использование в маршрутах:


  } />
  
        
      
    }
  />
  • useStore извлекает текущее состояние пользователя.
  • ProtectedRoute проверяет наличие пользователя и при необходимости перенаправляет на домашнюю страницу.

Синхронизация состояния с URL

React Router позволяет хранить параметры в URL, которые можно связать с состоянием Zustand.

Пример: фильтры и сортировка через URL

import { useSearchParams } from 'react-router-dom';
import { useStore } from './store';

function ProductList() {
  const [searchParams, setSearchParams] = useSearchParams();
  const setFilter = useStore((state) => state.setFilter);

  const filter = searchParams.get('filter') || '';
  setFilter(filter);

  const handleChange = (event) => {
    const value = event.target.value;
    setSearchParams({ filter: value });
    setFilter(value);
  };

  return ;
}
  • URL отражает текущее состояние фильтра.
  • Zustand хранит состояние, доступное в любом компоненте приложения.
  • Изменения URL автоматически обновляют состояние и наоборот.

Оптимизация производительности

Zustand позволяет выбирать конкретные части состояния для подписки, что снижает количество перерисовок:

const userName = useStore((state) => state.user?.name);
  • Только компоненты, использующие userName, будут перерисованы при изменении имени.
  • Остальные части интерфейса останутся неизменными.

Объединение нескольких хранилищ

Для крупных приложений удобно создавать несколько отдельных хранилищ Zustand и комбинировать их с маршрутами:

import { create } from 'zustand';

export const useAuthStore = create((set) => ({
  user: null,
  login: (user) => set({ user }),
  logout: () => set({ user: null }),
}));

export const useSettingsStore = create((set) => ({
  theme: 'light',
  setTheme: (theme) => set({ theme }),
}));
  • Разделение логики делает код более читаемым.
  • Компоненты маршрутов могут подключаться только к необходимому состоянию.

Работа с асинхронными действиями

Zustand поддерживает асинхронные функции напрямую в хранилище, что удобно для загрузки данных при навигации:

const useStore = create((set) => ({
  data: [],
  fetchData: async () => {
    const response = await fetch('/api/data');
    const json = await response.json();
    set({ data: json });
  },
}));
  • Асинхронные действия можно вызывать в эффектах компонентов, связанных с маршрутом.
  • Состояние хранится глобально и доступно на всех страницах.

Практический паттерн: состояние страницы + маршрутизация

  1. Каждая страница хранит своё локальное состояние через Zustand.
  2. URL содержит ключевые параметры состояния для восстановления при перезагрузке.
  3. ProtectedRoute или аналогичные компоненты контролируют доступ на основе глобального состояния.
  4. Асинхронные эффекты запускаются при изменении маршрута или параметров URL.

Такой подход обеспечивает:

  • согласованность состояния между страницами,
  • простую навигацию,
  • предсказуемое управление доступом и отображением компонентов.