Управление состоянием¶
Обзор¶
Приложение разделяет состояние на два уровня:
- Серверное состояние --- данные, полученные с сервера (списки документов, заданий, реестров, групп, настройки). Управляется библиотекой TanStack React Query.
- Местное состояние --- данные, существующие только в браузере (состояние формы, раскрытие панели, выбранный элемент). Управляется встроенными средствами React (
useState,useReducer).
Серверное состояние: React Query¶
Принцип работы¶
React Query автоматически:
- сохраняет ответы сервера и повторно использует их, пока данные не устареют;
- повторяет запрос при возникновении ошибки;
- обновляет данные в фоновом режиме, когда они считаются устаревшими;
- отменяет запрос, если компонент, запросивший данные, был удалён со страницы.
Настройка¶
Клиент запросов создаётся в App.tsx со следующими параметрами:
- Время устаревания --- одна минута. После получения ответа данные считаются свежими в течение минуты; при повторном обращении в этот период запрос к серверу не выполняется.
- Повторный запрос при возврате к окну --- отключён. Данные не обновляются автоматически, когда пользователь переключается обратно на вкладку приложения.
Получение данных: useQuery¶
Используется на всех страницах для получения списков и отдельных записей:
const { data: health, isLoading } = useQuery({
queryKey: ['health'],
queryFn: () => healthApi.check(),
refetchInterval: 30000,
})
Параметр queryKey определяет ключ сохранения. Если два компонента запрашивают данные с одинаковым ключом, запрос к серверу выполняется только один раз, а результат используется обоими.
Некоторые запросы настроены на периодическое обновление через refetchInterval --- например, проверка состояния системы каждые 30 секунд или отслеживание прогресса обработки.
Постраничная загрузка: useInfiniteQuery¶
Используется для загрузки длинных списков по частям --- например, при фильтрации значений колонки в таблице результатов реестра:
const { data, fetchNextPage, hasNextPage } = useInfiniteQuery({
queryKey: ['column-values', registryId, fieldId, search],
queryFn: ({ pageParam = 0 }) =>
registriesApi.getColumnValues(registryId, { skip: pageParam }),
getNextPageParam: (lastPage) => /* следующая порция */,
initialPageParam: 0,
})
При прокрутке списка вниз вызывается fetchNextPage, и следующая порция данных добавляется к уже загруженным.
Изменение данных: useMutation¶
Используется для отправки изменений на сервер (создание, обновление, удаление):
const confirmMutation = useMutation({
mutationFn: (groupId: string) => groupsApi.confirm(groupId),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['groups'] })
},
})
После успешного выполнения действия вызывается invalidateQueries, чтобы React Query повторно запросил актуальные данные с сервера. Это обеспечивает автоматическое обновление списка после подтверждения группы, удаления документа или изменения настроек.
Ключи сохранения¶
Каждый тип данных использует свой ключ:
| Ключ | Данные |
|---|---|
['health'] |
состояние системы |
['jobs'], ['jobs', 'recent'] |
задания обработки |
['documents'] |
список документов |
['groups'] |
группы документов |
['registries'] |
список реестров |
['registry', id] |
конкретный реестр |
['registry-rows', id] |
строки реестра |
['column-values', id, field] |
значения колонки для фильтрации |
['settings'] |
настройки приложения |
['archive'] |
дерево файлового архива |
Составные ключи (например, ['jobs', 'recent']) позволяют точечно обновлять хранилище: можно обновить только последние задания, не затрагивая полный список.
Местное состояние¶
Встроенные средства React¶
Для состояния, которое существует только внутри одного компонента или страницы, используются стандартные перехватчики React:
useState--- хранение простых значений: состояние раскрытия панели, текущий шаг мастера, содержимое поля ввода, выбранный элемент списка.useReducer--- хранение сложного состояния с несколькими связанными полями (используется в перехватчикеuseToastдля управления списком уведомлений).
Состояние в адресной строке¶
Часть состояния хранится в параметрах адресной строки через перехватчик useModalRouter. Это позволяет:
- сохранять открытые окна при обновлении страницы;
- использовать кнопки «Назад» и «Вперёд» для навигации между окнами;
- копировать ссылку на конкретный документ или исходный файл.
Подробнее --- в разделе маршрутизация.
Постоянное хранение в браузере¶
Единственное значение, сохраняемое в localStorage, --- состояние сворачивания бокового меню. При следующем визите боковое меню остаётся в том же положении, в котором его оставил пользователь.
Поток данных¶
Сервер (FastAPI)
↑↓ HTTP-запросы (Axios)
Прослойка обращений (api/client.ts)
↑↓ вызовы функций
React Query (хранилище в памяти браузера)
↑↓ перехватчики useQuery / useMutation
Компоненты страниц (pages/*.tsx)
↑↓ свойства и обратные вызовы
Базовые компоненты (components/ui/*.tsx)
Данные всегда проходят через React Query, даже если нужен единственный запрос. Это обеспечивает единообразное поведение: индикатор загрузки, обработка ошибок, автоматическое обновление.