Как лучше реализовать отображение спиннера на странице с элементами items, если при переключении между страницами и изменении фильтров необходимо показывать его, а при фоновом обновлении данных через pollingInterval - нет? Я использую RTK Query, который возвращает `isLoading` и `isFetching`, однако `isLoading` устанавливается в `true` только при первой загрузке компонента, тогда как `isFetching` - при каждом запросе, независимо от того, изменились ли параметры запроса или это обновление через polling. В данный момент у меня есть идея использовать отдельный state и `useEffect`, чтобы различать причины обновления данных, но этот подход кажется излишне сложным. Как обычно решают подобные задачи в таких случаях?
Для задачи, которую вы описываете, действительно можно использовать подход с состоянием и хуком `useEffect`, но также можно сделать это более элегантным образом, используя свойства `isFetching` и различные состояния компонентов.
### Основные идеи
1. **Используйте флаги для управления состоянием**:
- Создайте локальное состояние `isManuallyFetching` для отслеживания, происходит ли запрос при изменении параметров.
- Используйте `onSuccess` и `onError` в `refetch` для обновления этого состояния.
2. **Отображение спиннера**:
- Показывайте спиннер, когда `isFetching` истинно и `isManuallyFetching` также истинно.
- Это позволит вам избежать отображения спиннера при `polling`, так как он будет только для ручных обновлений.
### Пример реализации
```jsx
import React, { useEffect, useState } from 'react';
import { useLazyQuery } from '@reduxjs/toolkit/query/react';
import { myApi } from './api'; // Импортируем ваш api
const MyComponent = () => {
const [isManuallyFetching, setManuallyFetching] = useState(false);
const {
data: items,
isFetching,
refetch,
// добавьте другие нужные вам свойства
} = myApi.useGetItemsQuery();
// Используйте этот эффект для определения того, нужно ли показывать спиннер
useEffect(() => {
if (isFetching && isManuallyFetching) {
// Включаем спиннер
}
}, [isFetching, isManuallyFetching]);
const handleFilterChange = (newFilters) => {
setManuallyFetching(true);
refetch().then(() => setManuallyFetching(false));
};
return (
<div>
{isFetching && isManuallyFetching && <Spinner />}
{/* Тут отображение элементов */}
{items && items.map(item => <Item key={item.id} data={item} />)}
</div>
);
};
```
### Объяснение шагов:
1. **Локальное состояние `isManuallyFetching`**:
- Это состояние будет истинно только тогда, когда происходит ручной запрос из-за изменения фильтров или переключения страниц.
2. **Обновление состояния через `refetch`**:
- Когда вы вызываете `refetch`, устанавливаете `isManuallyFetching` в `true` перед запросом и сбрасываете его обратно в `false`, когда запрос завершен.
3. **Условное отображение спиннера**:
- Спиннер отображается только тогда, когда происходят ручные запросы и данные ещё загружаются (при `isFetching` и `isManuallyFetching`).
### Заключение
Такой подход позволит вам контролировать отображение спиннера более точно, избегая излишней сложности. Используйте состояния и эффекты разумно и в большинстве случаев сможете обеспечить адекватное поведение вашего интерфейса.
Вообщем пока я придумал только такое решение:
export const MyPage: React.FC = () => { const itemsPerPage = 50; const [searchText, setSearchText] = useState(''), [activePage, setActivePage] = useState(1), [filters, setFilters] = useState<Filters>({ status: 'all', category: '1' }); const { data, isLoading, isFetching, isSuccess, refetch, } = useSearchItemsQuery( { sortBy: sortBy, startAt: (activePage - 1) * itemsPerPage, maxResults: itemsPerPage, searchText, filters, }, { refetchOnFocus: true, pollingInterval: 30000 }, ); // Page loader const [showPageLoader, setShowPageLoader] = useState(true); useEffect(() => { setShowPageLoader(true); }, [activePage, itemsPerPage, sortBy, filters]); useEffect(() => { if (!isFetching) { setShowPageLoader(false); } }, [isFetching]); return ( <div> {data && items.map(item => <Item key={item.id} item={item} />)} <Spinner show={isLoading || (isFetching && showPageLoader) /> </div> ) }