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 4bb458778e
This commit is contained in:
schroda
2024-06-14 13:32:54 +02:00
parent 7266270075
commit 7337c18c7b
4 changed files with 26 additions and 9 deletions

View File

@@ -10,6 +10,8 @@ import React, { useContext, useEffect } from 'react';
import { INavbarOverride } from '@/typings'; import { INavbarOverride } from '@/typings';
type ContextType = { type ContextType = {
history: string[];
// Default back button url // Default back button url
defaultBackTo: string | undefined; defaultBackTo: string | undefined;
setDefaultBackTo: React.Dispatch<React.SetStateAction<string | undefined>>; setDefaultBackTo: React.Dispatch<React.SetStateAction<string | undefined>>;
@@ -28,6 +30,7 @@ type ContextType = {
}; };
export const NavBarContext = React.createContext<ContextType>({ export const NavBarContext = React.createContext<ContextType>({
history: [],
defaultBackTo: undefined, defaultBackTo: undefined,
setDefaultBackTo: (): void => {}, setDefaultBackTo: (): void => {},
title: 'Suwayomi', title: 'Suwayomi',

View File

@@ -9,6 +9,7 @@
import React, { useCallback, useMemo, useState } from 'react'; import React, { useCallback, useMemo, useState } from 'react';
import { INavbarOverride } from '@/typings'; import { INavbarOverride } from '@/typings';
import { NavBarContext } from '@/components/context/NavbarContext'; import { NavBarContext } from '@/components/context/NavbarContext';
import { useHistory } from '@/util/useHistory.ts';
interface IProps { interface IProps {
children: React.ReactNode; children: React.ReactNode;
@@ -23,6 +24,8 @@ export function NavBarContextProvider({ children }: IProps) {
value: <div />, value: <div />,
}); });
const history = useHistory();
const updateTitle = useCallback( const updateTitle = useCallback(
(newTitle: string | React.ReactNode, browserTitle: string = typeof newTitle === 'string' ? newTitle : '') => { (newTitle: string | React.ReactNode, browserTitle: string = typeof newTitle === 'string' ? newTitle : '') => {
document.title = `${browserTitle} - Suwayomi`; document.title = `${browserTitle} - Suwayomi`;
@@ -33,6 +36,7 @@ export function NavBarContextProvider({ children }: IProps) {
const value = useMemo( const value = useMemo(
() => ({ () => ({
history,
defaultBackTo, defaultBackTo,
setDefaultBackTo, setDefaultBackTo,
title, title,
@@ -42,7 +46,7 @@ export function NavBarContextProvider({ children }: IProps) {
override, override,
setOverride, setOverride,
}), }),
[defaultBackTo, setDefaultBackTo, title, updateTitle, action, setAction, override, setOverride], [history, defaultBackTo, setDefaultBackTo, title, updateTitle, action, setAction, override, setOverride],
); );
return <NavBarContext.Provider value={value}>{children}</NavBarContext.Provider>; return <NavBarContext.Provider value={value}>{children}</NavBarContext.Provider>;
} }

View File

@@ -8,14 +8,12 @@
import { useLocation, useNavigate } from 'react-router-dom'; import { useLocation, useNavigate } from 'react-router-dom';
import { useContext } from 'react'; import { useContext } from 'react';
import { useHistory } from '@/util/useHistory.ts';
import { NavBarContext } from '@/components/context/NavbarContext.tsx'; import { NavBarContext } from '@/components/context/NavbarContext.tsx';
export const useBackButton = () => { export const useBackButton = () => {
const navigate = useNavigate(); const navigate = useNavigate();
const history = useHistory();
const location = useLocation(); const location = useLocation();
const { defaultBackTo: backToUrl } = useContext(NavBarContext); const { history, defaultBackTo: backToUrl } = useContext(NavBarContext);
return () => { return () => {
const isHistoryEmpty = !history.length; const isHistoryEmpty = !history.length;

View File

@@ -6,14 +6,26 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. * 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'; import { NavigationType, useLocation, useNavigationType } from 'react-router-dom';
const MAX_DEPTH = 50;
export const useHistory = () => { export const useHistory = () => {
const location = useLocation(); const location = useLocation();
const navigationType = useNavigationType(); const navigationType = useNavigationType();
const [history, setHistory] = useState<string[]>([]); const [history, setHistory] = useState<string[]>([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(() => { useEffect(() => {
const isLastPageInHistory = location.key === 'default'; const isLastPageInHistory = location.key === 'default';
@@ -24,13 +36,13 @@ export const useHistory = () => {
switch (navigationType) { switch (navigationType) {
case NavigationType.Pop: case NavigationType.Pop:
setHistory([...history.slice(0, -1)]); updateHistory([...history.slice(0, -1)]);
break; break;
case NavigationType.Push: case NavigationType.Push:
setHistory([...history, location.pathname]); updateHistory([...history, location.pathname]);
break; break;
case NavigationType.Replace: case NavigationType.Replace:
setHistory([...history.slice(0, -1), location.pathname]); updateHistory([...history.slice(0, -1), location.pathname]);
break; break;
default: default:
throw new Error(`Unexpected NavigationType "${navigationType}"`); throw new Error(`Unexpected NavigationType "${navigationType}"`);