From 9ce273b5ced0afce5f86f33a6c2086db315e6b18 Mon Sep 17 00:00:00 2001 From: schroda <50052685+schroda@users.noreply.github.com> Date: Fri, 20 Mar 2026 03:02:52 +0100 Subject: [PATCH] Use stable array/object constants --- src/base/components/SpinnerImage.tsx | 3 ++- src/base/components/feedback/Progress.tsx | 3 ++- src/base/components/menu/NestedMenuItem.tsx | 3 ++- src/base/hooks/useIntersectionObserver.tsx | 3 ++- src/features/chapter/components/ChapterList.tsx | 3 ++- .../chapter/components/actions/ChapterActionMenuItems.tsx | 3 ++- src/features/downloads/screens/DownloadQueue.tsx | 3 ++- src/features/global-search/screens/SearchAll.tsx | 5 +++-- src/features/history/screens/History.tsx | 3 ++- src/features/library/screens/Library.tsx | 6 ++++-- src/features/manga/components/MangaActionMenuItems.tsx | 3 ++- src/features/navigation-bar/hooks/useAppAction.ts | 3 ++- .../components/ReaderNavBarDesktopChapterNavigation.tsx | 3 ++- src/features/source/browse/components/SourceOptions.tsx | 3 ++- src/features/source/browse/screens/SourceMangas.tsx | 7 ++++--- .../source/configuration/screens/SourceConfigure.tsx | 3 ++- src/features/tracker/components/TrackManga.tsx | 5 +++-- src/features/tracker/screens/TrackingSettings.tsx | 3 ++- src/features/updates/screens/Updates.tsx | 3 ++- 19 files changed, 44 insertions(+), 24 deletions(-) diff --git a/src/base/components/SpinnerImage.tsx b/src/base/components/SpinnerImage.tsx index 6fc4c7c7..74a1bc93 100644 --- a/src/base/components/SpinnerImage.tsx +++ b/src/base/components/SpinnerImage.tsx @@ -8,6 +8,7 @@ import type { Ref } from 'react'; import { useState, useEffect, useCallback, useRef } from 'react'; +import { STABLE_EMPTY_OBJECT } from '@/base/Base.constants.ts'; import CircularProgress from '@mui/material/CircularProgress'; import Box from '@mui/material/Box'; import Stack from '@mui/material/Stack'; @@ -61,7 +62,7 @@ export const SpinnerImage = ({ ref, ...props }: SpinnerImageProps) => { alt, onLoad, onError, - spinnerStyle: { small, ...spinnerStyle } = {}, + spinnerStyle: { small, ...spinnerStyle } = STABLE_EMPTY_OBJECT, imgStyle, hideImgStyle, priority, diff --git a/src/base/components/feedback/Progress.tsx b/src/base/components/feedback/Progress.tsx index f0451da9..4e16759c 100644 --- a/src/base/components/feedback/Progress.tsx +++ b/src/base/components/feedback/Progress.tsx @@ -10,11 +10,12 @@ import Box from '@mui/material/Box'; import type { CircularProgressProps } from '@mui/material/CircularProgress'; import CircularProgress from '@mui/material/CircularProgress'; import Typography from '@mui/material/Typography'; +import { STABLE_EMPTY_OBJECT } from '@/base/Base.constants.ts'; export const Progress = ({ progress, showText = true, - progressProps = {}, + progressProps = STABLE_EMPTY_OBJECT, }: { progress: number; showText?: boolean; diff --git a/src/base/components/menu/NestedMenuItem.tsx b/src/base/components/menu/NestedMenuItem.tsx index b581c9c1..ed042c3d 100644 --- a/src/base/components/menu/NestedMenuItem.tsx +++ b/src/base/components/menu/NestedMenuItem.tsx @@ -12,6 +12,7 @@ * with a few changes to fix a bug on mobile devices where opening the sub menu immediately triggered the on click of the underlying menu item */ +import { STABLE_EMPTY_OBJECT } from '@/base/Base.constants.ts'; import type { MenuProps as MuiMenuProps } from '@mui/material/Menu'; import Menu from '@mui/material/Menu'; import type { MenuItemProps as MuiMenuItemProps } from '@mui/material/MenuItem'; @@ -64,7 +65,7 @@ export const NestedMenuItem = ({ ref, ...props }: NestedMenuItemProps) => { children, className, tabIndex: tabIndexProp, - ContainerProps: ContainerPropsProp = {}, + ContainerProps: ContainerPropsProp = STABLE_EMPTY_OBJECT, MenuProps, ...MenuItemProps } = props; diff --git a/src/base/hooks/useIntersectionObserver.tsx b/src/base/hooks/useIntersectionObserver.tsx index d30ddde5..371552a4 100644 --- a/src/base/hooks/useIntersectionObserver.tsx +++ b/src/base/hooks/useIntersectionObserver.tsx @@ -8,6 +8,7 @@ import type { RefObject } from 'react'; import { useLayoutEffect, useState } from 'react'; +import { STABLE_EMPTY_OBJECT } from '@/base/Base.constants.ts'; export const useIntersectionObserver = ( ref: RefObject | HTMLElement | undefined | null, @@ -17,7 +18,7 @@ export const useIntersectionObserver = ( root, rootMargin, threshold, - }: IntersectionObserverInit & { ignoreInitialObserve?: boolean } = {}, + }: IntersectionObserverInit & { ignoreInitialObserve?: boolean } = STABLE_EMPTY_OBJECT, ): (() => void) => { const [disconnect, setDisconnect] = useState<() => void>(() => {}); diff --git a/src/features/chapter/components/ChapterList.tsx b/src/features/chapter/components/ChapterList.tsx index 8c540828..4a4f9005 100644 --- a/src/features/chapter/components/ChapterList.tsx +++ b/src/features/chapter/components/ChapterList.tsx @@ -46,6 +46,7 @@ import { getErrorMessage } from '@/lib/HelperFunctions.ts'; import { makeToast } from '@/base/utils/Toast.ts'; import { ChapterListCard } from '@/features/chapter/components/cards/ChapterListCard.tsx'; import { VirtuosoPersisted } from '@/lib/virtuoso/Component/VirtuosoPersisted.tsx'; +import { STABLE_EMPTY_ARRAY } from '@/base/Base.constants.ts'; type ChapterListHeaderProps = { scrollbarWidth: number; @@ -140,7 +141,7 @@ export const ChapterList = ({ manga.id, { notifyOnNetworkStatusChange: true }, ); - const chapters = useMemo(() => chaptersData?.chapters.nodes ?? [], [chaptersData?.chapters.nodes]); + const chapters = chaptersData?.chapters.nodes ?? STABLE_EMPTY_ARRAY; const visibleChapters = useMemo(() => filterAndSortChapters(chapters, options), [chapters, options]); const visibleChapterIds = useMemo(() => Chapters.getIds(visibleChapters), [visibleChapters]); diff --git a/src/features/chapter/components/actions/ChapterActionMenuItems.tsx b/src/features/chapter/components/actions/ChapterActionMenuItems.tsx index 25d0b267..df106f28 100644 --- a/src/features/chapter/components/actions/ChapterActionMenuItems.tsx +++ b/src/features/chapter/components/actions/ChapterActionMenuItems.tsx @@ -6,6 +6,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +import { STABLE_EMPTY_ARRAY } from '@/base/Base.constants.ts'; import CheckBoxOutlineBlank from '@mui/icons-material/CheckBoxOutlineBlank'; import Delete from '@mui/icons-material/Delete'; import Download from '@mui/icons-material/Download'; @@ -71,7 +72,7 @@ export const ChapterActionMenuItems = ({ chapter, handleSelection, canBeDownloaded = false, - selectedChapters = [], + selectedChapters = STABLE_EMPTY_ARRAY, onClose, selectable = true, }: Props) => { diff --git a/src/features/downloads/screens/DownloadQueue.tsx b/src/features/downloads/screens/DownloadQueue.tsx index a1ae27de..f085f597 100644 --- a/src/features/downloads/screens/DownloadQueue.tsx +++ b/src/features/downloads/screens/DownloadQueue.tsx @@ -33,6 +33,7 @@ import { useAppTitle } from '@/features/navigation-bar/hooks/useAppTitle.ts'; import { useAppAction } from '@/features/navigation-bar/hooks/useAppAction.ts'; import type { ChapterDownloadStatus } from '@/features/chapter/Chapter.types.ts'; import { VirtuosoPersisted } from '@/lib/virtuoso/Component/VirtuosoPersisted.tsx'; +import { STABLE_EMPTY_ARRAY } from '@/base/Base.constants.ts'; export const DownloadQueue: React.FC = () => { const { t } = useLingui(); @@ -49,7 +50,7 @@ export const DownloadQueue: React.FC = () => { } = requestManager.useGetDownloadStatus({ notifyOnNetworkStatusChange: true }); const downloaderData = downloadStatusData?.downloadStatus; - const queue = downloaderData?.queue ?? []; + const queue = downloaderData?.queue ?? STABLE_EMPTY_ARRAY; const status = downloaderData?.state ?? DownloaderState.Started; const isQueueEmpty = !queue.length; diff --git a/src/features/global-search/screens/SearchAll.tsx b/src/features/global-search/screens/SearchAll.tsx index 6c3b0e66..091acfe6 100644 --- a/src/features/global-search/screens/SearchAll.tsx +++ b/src/features/global-search/screens/SearchAll.tsx @@ -28,6 +28,7 @@ import { AppbarSearch } from '@/base/components/AppbarSearch.tsx'; import { useDebounce } from '@/base/hooks/useDebounce.ts'; import type { MangaCardProps } from '@/features/manga/Manga.types.ts'; import { EmptyView } from '@/base/components/feedback/EmptyView.tsx'; +import { STABLE_EMPTY_ARRAY } from '@/base/Base.constants.ts'; import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts'; import { LoadingPlaceholder } from '@/base/components/feedback/LoadingPlaceholder.tsx'; import { BaseMangaGrid } from '@/features/manga/components/BaseMangaGrid.tsx'; @@ -254,7 +255,7 @@ export const SearchAll: React.FC = () => { } = useMetadataServerSettings(); const { data, loading, error, refetch } = requestManager.useGetSourceList({ notifyOnNetworkStatusChange: true }); - const sources = useMemo(() => data?.sources.nodes ?? [], [data?.sources.nodes]); + const sources = data?.sources.nodes ?? STABLE_EMPTY_ARRAY; const [sourceToLoadingStateMap, setSourceToLoadingStateMap] = useState(new Map()); const debouncedSourceToLoadingStateMap = useDebounce(sourceToLoadingStateMap, 500); @@ -304,7 +305,7 @@ export const SearchAll: React.FC = () => { selectedLanguages={shownLangs} setSelectedLanguages={setShownLangs} languages={sourceLanguages} - sources={sources ?? []} + sources={sources} /> , [shownLangs, setShownLangs, sourceLanguages, sources], diff --git a/src/features/history/screens/History.tsx b/src/features/history/screens/History.tsx index 51e48866..42dd6d43 100644 --- a/src/features/history/screens/History.tsx +++ b/src/features/history/screens/History.tsx @@ -21,6 +21,7 @@ import { getErrorMessage } from '@/lib/HelperFunctions.ts'; import { ChapterHistoryCard } from '@/features/history/components/ChapterHistoryCard.tsx'; import { Chapters } from '@/features/chapter/services/Chapters.ts'; import { useAppTitle } from '@/features/navigation-bar/hooks/useAppTitle.ts'; +import { STABLE_EMPTY_ARRAY } from '@/base/Base.constants.ts'; export const History: React.FC = () => { const { t } = useLingui(); @@ -39,7 +40,7 @@ export const History: React.FC = () => { }); const hasNextPage = !!chapterHistoryData?.chapters.pageInfo.hasNextPage; const endCursor = chapterHistoryData?.chapters.pageInfo.endCursor; - const readEntries = chapterHistoryData?.chapters.nodes ?? []; + const readEntries = chapterHistoryData?.chapters.nodes ?? STABLE_EMPTY_ARRAY; const groupedHistory = useMemo( () => Object.entries(Chapters.groupByDate(readEntries, 'lastReadAt')), [readEntries], diff --git a/src/features/library/screens/Library.tsx b/src/features/library/screens/Library.tsx index d487d65f..55b4d0c8 100644 --- a/src/features/library/screens/Library.tsx +++ b/src/features/library/screens/Library.tsx @@ -50,6 +50,7 @@ import { useAppTitle } from '@/features/navigation-bar/hooks/useAppTitle.ts'; import { useAppAction } from '@/features/navigation-bar/hooks/useAppAction.ts'; import { AppRoutes } from '@/base/AppRoute.constants.ts'; import { SearchParam } from '@/base/Base.types.ts'; +import { STABLE_EMPTY_ARRAY } from '@/base/Base.constants.ts'; const TitleWithSizeTag = styled('span')({ display: 'flex', @@ -82,7 +83,7 @@ export function Library() { const tabsData = categoriesResponse?.categories.nodes.filter( (category) => category.id !== 0 || (category.id === 0 && category.mangas.totalCount), ); - const tabs = tabsData ?? []; + const tabs = tabsData ?? STABLE_EMPTY_ARRAY; const librarySizeResponse = requestManager.useGetMangas< GetLibraryMangaCountQuery, @@ -102,7 +103,7 @@ export function Library() { loading: mangaLoading, refetch: refetchCategoryMangas, } = requestManager.useGetCategoryMangas(activeTab?.id, { skip: !activeTab, notifyOnNetworkStatusChange: true }); - const categoryMangas = categoryMangaResponse?.mangas.nodes ?? []; + const categoryMangas = categoryMangaResponse?.mangas.nodes ?? STABLE_EMPTY_ARRAY; const { visibleMangas: mangas, showFilteredOutMessage, @@ -127,6 +128,7 @@ export function Library() { } = useSelectableCollection(mangas.length, { itemIds: mangaIds, currentKey: activeTab?.id.toString(), + initialState: undefined, }); const handleSelect: typeof handleSelection = useCallback( diff --git a/src/features/manga/components/MangaActionMenuItems.tsx b/src/features/manga/components/MangaActionMenuItems.tsx index 9a76f76b..a1aafb15 100644 --- a/src/features/manga/components/MangaActionMenuItems.tsx +++ b/src/features/manga/components/MangaActionMenuItems.tsx @@ -37,6 +37,7 @@ import type { MangaAction, MangaDownloadInfo, MangaIdInfo, MangaUnreadInfo } fro import { MANGA_ACTION_TO_TRANSLATION } from '@/features/manga/Manga.constants.ts'; import { AppRoutes } from '@/base/AppRoute.constants.ts'; import { CategorySelect } from '@/features/category/components/CategorySelect.tsx'; +import { STABLE_EMPTY_ARRAY } from '@/base/Base.constants.ts'; type BaseProps = { onClose: () => void; setHideMenu: (hide: boolean) => void }; @@ -65,7 +66,7 @@ export const MangaActionMenuItems = ({ const [isTrackDialogOpen, setIsTrackDialogOpen] = useState(false); const isSingleMode = !!manga; - const selectedMangas = passedSelectedMangas ?? []; + const selectedMangas = passedSelectedMangas ?? STABLE_EMPTY_ARRAY; const getMenuItemTitle = createGetMenuItemTitle(isSingleMode, MANGA_ACTION_TO_TRANSLATION); const shouldShowMenuItem = createShouldShowMenuItem(isSingleMode); diff --git a/src/features/navigation-bar/hooks/useAppAction.ts b/src/features/navigation-bar/hooks/useAppAction.ts index 1c068716..2ecfa8c7 100644 --- a/src/features/navigation-bar/hooks/useAppAction.ts +++ b/src/features/navigation-bar/hooks/useAppAction.ts @@ -9,8 +9,9 @@ import { useEffect } from 'react'; import { useNavBarContext } from '@/features/navigation-bar/NavbarContext.tsx'; import type { NavbarContextType } from '@/features/navigation-bar/NavigationBar.types.ts'; +import { STABLE_EMPTY_ARRAY } from '@/base/Base.constants.ts'; -export const useAppAction = (action: NavbarContextType['action'], dependencies: any[] = []) => { +export const useAppAction = (action: NavbarContextType['action'], dependencies: any[] = STABLE_EMPTY_ARRAY) => { const { setAction } = useNavBarContext(); useEffect(() => { diff --git a/src/features/reader/overlay/navigation/desktop/components/ReaderNavBarDesktopChapterNavigation.tsx b/src/features/reader/overlay/navigation/desktop/components/ReaderNavBarDesktopChapterNavigation.tsx index 85817095..c8884c24 100644 --- a/src/features/reader/overlay/navigation/desktop/components/ReaderNavBarDesktopChapterNavigation.tsx +++ b/src/features/reader/overlay/navigation/desktop/components/ReaderNavBarDesktopChapterNavigation.tsx @@ -6,6 +6,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +import { STABLE_EMPTY_ARRAY } from '@/base/Base.constants.ts'; import Stack from '@mui/material/Stack'; import Box from '@mui/material/Box'; import MenuItem from '@mui/material/MenuItem'; @@ -32,7 +33,7 @@ const BaseReaderNavBarDesktopChapterNavigation = ({ currentChapterNumber, previousChapter, nextChapter, - chapters = [], + chapters = STABLE_EMPTY_ARRAY, readerThemeDirection, }: { currentChapterId: ChapterIdInfo['id'] | undefined; diff --git a/src/features/source/browse/components/SourceOptions.tsx b/src/features/source/browse/components/SourceOptions.tsx index b5c3776d..1c1cc220 100644 --- a/src/features/source/browse/components/SourceOptions.tsx +++ b/src/features/source/browse/components/SourceOptions.tsx @@ -6,6 +6,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +import { STABLE_EMPTY_OBJECT } from '@/base/Base.constants.ts'; import FilterListIcon from '@mui/icons-material/FilterList'; import Button from '@mui/material/Button'; import Stack from '@mui/material/Stack'; @@ -159,7 +160,7 @@ export function Options({ sourceFilter, group, updateFilterValue, update }: IFil } export function SourceOptions({ - savedSearches = {}, + savedSearches = STABLE_EMPTY_OBJECT, selectSavedSearch, updateSavedSearches, sourceFilter, diff --git a/src/features/source/browse/screens/SourceMangas.tsx b/src/features/source/browse/screens/SourceMangas.tsx index 790cecba..e24edab1 100644 --- a/src/features/source/browse/screens/SourceMangas.tsx +++ b/src/features/source/browse/screens/SourceMangas.tsx @@ -52,6 +52,7 @@ import { GridLayout, SearchParam } from '@/base/Base.types'; import { AppRoutes } from '@/base/AppRoute.constants.ts'; import { getErrorMessage } from '@/lib/HelperFunctions.ts'; import { Sources } from '@/features/source/services/Sources.ts'; +import { STABLE_EMPTY_ARRAY, STABLE_EMPTY_OBJECT } from '@/base/Base.constants.ts'; import { useAppTitleAndAction } from '@/features/navigation-bar/hooks/useAppTitleAndAction.ts'; import { useNavBarContext } from '@/features/navigation-bar/NavbarContext.tsx'; import { VirtuosoUtil } from '@/lib/virtuoso/Virtuoso.util.tsx'; @@ -219,7 +220,7 @@ export function SourceMangas() { useLocation<{ contentType: SourceContentType; clearCache: boolean; - }>().state ?? {}; + }>().state ?? STABLE_EMPTY_OBJECT; const { settings: { hideLibraryEntries }, @@ -288,7 +289,7 @@ export function SourceMangas() { { data, error, isLoading: loading, size: lastPageNum, abortRequest, filteredOutAllItemsOfFetchedPage }, ] = useSourceManga(sourceId, contentType, query, filtersToApply, 1, hideLibraryEntries); currentAbortRequest.current = abortRequest; - const mangas = data?.fetchSourceManga?.mangas ?? []; + const mangas = data?.fetchSourceManga?.mangas ?? STABLE_EMPTY_ARRAY; const hasNextPage = !!data?.fetchSourceManga?.hasNextPage; const isLoading = loading || (filteredOutAllItemsOfFetchedPage && hasNextPage); const { data: sourceData } = requestManager.useGetSource( @@ -297,7 +298,7 @@ export function SourceMangas() { ); const source = sourceData?.source; - const filters = source?.filters ?? []; + const filters = source?.filters ?? STABLE_EMPTY_ARRAY; const { savedSearches = {} } = useGetSourceMetadata(source ?? DEFAULT_SOURCE); const updateSourceMetadata = createUpdateSourceMetadata<'savedSearches'>(source ?? { id: '-1' }, (e) => makeToast(t`Failed to save changes`, 'error', getErrorMessage(e)), diff --git a/src/features/source/configuration/screens/SourceConfigure.tsx b/src/features/source/configuration/screens/SourceConfigure.tsx index e8b0966a..20f97824 100644 --- a/src/features/source/configuration/screens/SourceConfigure.tsx +++ b/src/features/source/configuration/screens/SourceConfigure.tsx @@ -28,6 +28,7 @@ import { makeToast } from '@/base/utils/Toast.ts'; import type { PreferenceProps } from '@/features/source/Source.types.ts'; import { getErrorMessage } from '@/lib/HelperFunctions.ts'; import { useAppTitle } from '@/features/navigation-bar/hooks/useAppTitle.ts'; +import { STABLE_EMPTY_ARRAY } from '@/base/Base.constants.ts'; function getPrefComponent(type: string) { switch (type) { @@ -58,7 +59,7 @@ export function SourceConfigure() { >(GET_SOURCE_SETTINGS, sourceId, { notifyOnNetworkStatusChange: true, }); - const sourcePreferences = data?.source.preferences ?? []; + const sourcePreferences = data?.source.preferences ?? STABLE_EMPTY_ARRAY; const updateValue = (position: number): PreferenceProps['updateValue'] => diff --git a/src/features/tracker/components/TrackManga.tsx b/src/features/tracker/components/TrackManga.tsx index 6658cebb..824b593c 100644 --- a/src/features/tracker/components/TrackManga.tsx +++ b/src/features/tracker/components/TrackManga.tsx @@ -24,6 +24,7 @@ import type { MangaIdInfo } from '@/features/manga/Manga.types.ts'; import { AppRoutes } from '@/base/AppRoute.constants.ts'; import { getErrorMessage } from '@/lib/HelperFunctions.ts'; import { EmptyView } from '@/base/components/feedback/EmptyView.tsx'; +import { STABLE_EMPTY_ARRAY } from '@/base/Base.constants.ts'; const getTrackerMode = (id: number, trackersInUse: number[], searchModeForTracker?: number): TrackerMode => { if (id === searchModeForTracker) { @@ -46,13 +47,13 @@ export const TrackManga = ({ manga }: { manga: MangaIdInfo & Pick(GET_TRACKERS_BIND, { notifyOnNetworkStatusChange: true, }); - const trackers = trackerList.data?.trackers.nodes ?? []; + const trackers = trackerList.data?.trackers.nodes ?? STABLE_EMPTY_ARRAY; const mangaTrackRecordsList = requestManager.useGetManga( GET_MANGA_TRACK_RECORDS, manga.id, ); - const mangaTrackRecords = mangaTrackRecordsList.data?.manga.trackRecords.nodes ?? []; + const mangaTrackRecords = mangaTrackRecordsList.data?.manga.trackRecords.nodes ?? STABLE_EMPTY_ARRAY; const loggedInTrackers = Trackers.getLoggedIn(trackers); const trackersInUse = Trackers.getLoggedIn(Trackers.getTrackers(mangaTrackRecords, trackers)); diff --git a/src/features/tracker/screens/TrackingSettings.tsx b/src/features/tracker/screens/TrackingSettings.tsx index a6296993..dc5ce863 100644 --- a/src/features/tracker/screens/TrackingSettings.tsx +++ b/src/features/tracker/screens/TrackingSettings.tsx @@ -27,6 +27,7 @@ import type { GetTrackersSettingsQuery } from '@/lib/graphql/generated/graphql.t import type { MetadataTrackingSettings } from '@/features/tracker/Tracker.types.ts'; import { getErrorMessage } from '@/lib/HelperFunctions.ts'; import { useAppTitle } from '@/features/navigation-bar/hooks/useAppTitle.ts'; +import { STABLE_EMPTY_ARRAY } from '@/base/Base.constants.ts'; export const TrackingSettings = () => { const { t } = useLingui(); @@ -50,7 +51,7 @@ export const TrackingSettings = () => { } = requestManager.useGetTrackerList(GET_TRACKERS_SETTINGS, { notifyOnNetworkStatusChange: true, }); - const trackers = data?.trackers.nodes ?? []; + const trackers = data?.trackers.nodes ?? STABLE_EMPTY_ARRAY; const loading = areMetadataServerSettingsLoading || areTrackersLoading; const error = metadataServerSettingsError ?? trackersError; diff --git a/src/features/updates/screens/Updates.tsx b/src/features/updates/screens/Updates.tsx index eeac5723..2ef8bd8e 100644 --- a/src/features/updates/screens/Updates.tsx +++ b/src/features/updates/screens/Updates.tsx @@ -25,6 +25,7 @@ import { useNavBarContext } from '@/features/navigation-bar/NavbarContext.tsx'; import { Chapters } from '@/features/chapter/services/Chapters.ts'; import { useAppTitleAndAction } from '@/features/navigation-bar/hooks/useAppTitleAndAction.ts'; import { GROUPED_VIRTUOSO_Z_INDEX } from '@/lib/virtuoso/Virtuoso.constants.ts'; +import { STABLE_EMPTY_ARRAY } from '@/base/Base.constants.ts'; export const Updates: React.FC = () => { const { t } = useLingui(); @@ -42,7 +43,7 @@ export const Updates: React.FC = () => { }); const hasNextPage = !!chapterUpdateData?.chapters.pageInfo.hasNextPage; const endCursor = chapterUpdateData?.chapters.pageInfo.endCursor; - const updateEntries = chapterUpdateData?.chapters.nodes ?? []; + const updateEntries = chapterUpdateData?.chapters.nodes ?? STABLE_EMPTY_ARRAY; const groupedUpdates = useMemo( () => Object.entries(Chapters.groupByDate(updateEntries, 'fetchedAt')), [updateEntries],