From 7337c18c7bff20c63c513ebe3d3bfea903ed7cb5 Mon Sep 17 00:00:00 2001 From: schroda <50052685+schroda@users.noreply.github.com> Date: Fri, 14 Jun 2024 13:32:54 +0200 Subject: [PATCH] Use global navigation history stack The readers history stack was different to the one from the rest of the app, resulting in an infinite loop when using the closing the reader and using the back button in the manga page, since the back button just opened the reader again. Regression introduced with 4bb458778e715e564449f60c5778da44dd7b22cf --- src/components/context/NavbarContext.tsx | 3 +++ .../navbar/NavBarContextProvider.tsx | 6 ++++- src/util/useBackButton.ts | 4 +--- src/util/useHistory.ts | 22 ++++++++++++++----- 4 files changed, 26 insertions(+), 9 deletions(-) diff --git a/src/components/context/NavbarContext.tsx b/src/components/context/NavbarContext.tsx index af7a8619..de65ebf6 100644 --- a/src/components/context/NavbarContext.tsx +++ b/src/components/context/NavbarContext.tsx @@ -10,6 +10,8 @@ import React, { useContext, useEffect } from 'react'; import { INavbarOverride } from '@/typings'; type ContextType = { + history: string[]; + // Default back button url defaultBackTo: string | undefined; setDefaultBackTo: React.Dispatch>; @@ -28,6 +30,7 @@ type ContextType = { }; export const NavBarContext = React.createContext({ + history: [], defaultBackTo: undefined, setDefaultBackTo: (): void => {}, title: 'Suwayomi', diff --git a/src/components/navbar/NavBarContextProvider.tsx b/src/components/navbar/NavBarContextProvider.tsx index ed6fca76..650ce310 100644 --- a/src/components/navbar/NavBarContextProvider.tsx +++ b/src/components/navbar/NavBarContextProvider.tsx @@ -9,6 +9,7 @@ import React, { useCallback, useMemo, useState } from 'react'; import { INavbarOverride } from '@/typings'; import { NavBarContext } from '@/components/context/NavbarContext'; +import { useHistory } from '@/util/useHistory.ts'; interface IProps { children: React.ReactNode; @@ -23,6 +24,8 @@ export function NavBarContextProvider({ children }: IProps) { value:
, }); + const history = useHistory(); + const updateTitle = useCallback( (newTitle: string | React.ReactNode, browserTitle: string = typeof newTitle === 'string' ? newTitle : '') => { document.title = `${browserTitle} - Suwayomi`; @@ -33,6 +36,7 @@ export function NavBarContextProvider({ children }: IProps) { const value = useMemo( () => ({ + history, defaultBackTo, setDefaultBackTo, title, @@ -42,7 +46,7 @@ export function NavBarContextProvider({ children }: IProps) { override, setOverride, }), - [defaultBackTo, setDefaultBackTo, title, updateTitle, action, setAction, override, setOverride], + [history, defaultBackTo, setDefaultBackTo, title, updateTitle, action, setAction, override, setOverride], ); return {children}; } diff --git a/src/util/useBackButton.ts b/src/util/useBackButton.ts index 7fe77e93..4641d179 100644 --- a/src/util/useBackButton.ts +++ b/src/util/useBackButton.ts @@ -8,14 +8,12 @@ import { useLocation, useNavigate } from 'react-router-dom'; import { useContext } from 'react'; -import { useHistory } from '@/util/useHistory.ts'; import { NavBarContext } from '@/components/context/NavbarContext.tsx'; export const useBackButton = () => { const navigate = useNavigate(); - const history = useHistory(); const location = useLocation(); - const { defaultBackTo: backToUrl } = useContext(NavBarContext); + const { history, defaultBackTo: backToUrl } = useContext(NavBarContext); return () => { const isHistoryEmpty = !history.length; diff --git a/src/util/useHistory.ts b/src/util/useHistory.ts index 2aa9bf20..840a8eb5 100644 --- a/src/util/useHistory.ts +++ b/src/util/useHistory.ts @@ -6,14 +6,26 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -import { useEffect, useState } from 'react'; +import { useCallback, useEffect, useState } from 'react'; import { NavigationType, useLocation, useNavigationType } from 'react-router-dom'; +const MAX_DEPTH = 50; + export const useHistory = () => { const location = useLocation(); const navigationType = useNavigationType(); - const [history, setHistory] = useState([]); + const [history, setHistory] = useState([location.pathname]); + + const updateHistory = useCallback((newHistory: string[]) => { + // prevent the history from getting too large (only relevant in case the app never gets reloaded (e.g. browser F5, + // electron window gets closed)) + // theoretically the history should be empty for the "base" pages (e.g. library, updates, ...), but since the browser + // navigation is used, opening another base page pushes this page to this history, as if it had a different depth + // than the current page (expected history: library -> manga -> reader, + // possible history: library -> updates -> settings -> library -> manga -> reader) + setHistory(newHistory.slice(-MAX_DEPTH)); + }, []); useEffect(() => { const isLastPageInHistory = location.key === 'default'; @@ -24,13 +36,13 @@ export const useHistory = () => { switch (navigationType) { case NavigationType.Pop: - setHistory([...history.slice(0, -1)]); + updateHistory([...history.slice(0, -1)]); break; case NavigationType.Push: - setHistory([...history, location.pathname]); + updateHistory([...history, location.pathname]); break; case NavigationType.Replace: - setHistory([...history.slice(0, -1), location.pathname]); + updateHistory([...history.slice(0, -1), location.pathname]); break; default: throw new Error(`Unexpected NavigationType "${navigationType}"`);