Как лучше реализовать отображение спиннера на странице с элементами 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> ) }