Restore virtuoso states on browser back navigation
- manga chapter list - library duplicates - updates - history - download queue
This commit is contained in:
38
src/lib/virtuoso/Component/GroupedVirtuosoPersisted.tsx
Normal file
38
src/lib/virtuoso/Component/GroupedVirtuosoPersisted.tsx
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) Contributors to the Suwayomi project
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
import { ComponentProps, useRef } from 'react';
|
||||
import { GroupedVirtuoso, GroupedVirtuosoHandle, StateSnapshot } from 'react-virtuoso';
|
||||
import { useMergedRef } from '@mantine/hooks';
|
||||
import { VirtuosoUtil } from '@/lib/virtuoso/Virtuoso.util.tsx';
|
||||
|
||||
export const GroupedVirtuosoPersisted = ({
|
||||
ref: passedRef,
|
||||
persistKey,
|
||||
...props
|
||||
}: ComponentProps<typeof GroupedVirtuoso> & { persistKey: string }) => {
|
||||
const { state, persistState } = VirtuosoUtil.usePersistState<StateSnapshot>(persistKey);
|
||||
|
||||
const localRef = useRef<GroupedVirtuosoHandle>(undefined);
|
||||
const ref = useMergedRef(localRef, passedRef);
|
||||
|
||||
return (
|
||||
<GroupedVirtuoso
|
||||
{...props}
|
||||
ref={ref}
|
||||
isScrolling={(isScrolling) => {
|
||||
if (!isScrolling) {
|
||||
localRef.current?.getState(persistState);
|
||||
}
|
||||
|
||||
props.isScrolling?.(isScrolling);
|
||||
}}
|
||||
restoreStateFrom={state}
|
||||
/>
|
||||
);
|
||||
};
|
||||
25
src/lib/virtuoso/Component/VirtuosoGridPersisted.tsx
Normal file
25
src/lib/virtuoso/Component/VirtuosoGridPersisted.tsx
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) Contributors to the Suwayomi project
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
import { ComponentProps, useRef } from 'react';
|
||||
import { GridStateSnapshot, VirtuosoGrid, VirtuosoGridHandle } from 'react-virtuoso';
|
||||
import { useMergedRef } from '@mantine/hooks';
|
||||
import { VirtuosoUtil } from '@/lib/virtuoso/Virtuoso.util.tsx';
|
||||
|
||||
export const VirtuosoGridPersisted = ({
|
||||
ref: passedRef,
|
||||
persistKey,
|
||||
...props
|
||||
}: ComponentProps<typeof VirtuosoGrid> & { persistKey: string }) => {
|
||||
const { state, persistState } = VirtuosoUtil.usePersistState<GridStateSnapshot>(persistKey);
|
||||
|
||||
const localRef = useRef<VirtuosoGridHandle>(undefined);
|
||||
const ref = useMergedRef(localRef, passedRef);
|
||||
|
||||
return <VirtuosoGrid {...props} ref={ref} stateChanged={persistState} restoreStateFrom={state} />;
|
||||
};
|
||||
38
src/lib/virtuoso/Component/VirtuosoPersisted.tsx
Normal file
38
src/lib/virtuoso/Component/VirtuosoPersisted.tsx
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) Contributors to the Suwayomi project
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
import { ComponentProps, useRef } from 'react';
|
||||
import { StateSnapshot, Virtuoso, VirtuosoHandle } from 'react-virtuoso';
|
||||
import { useMergedRef } from '@mantine/hooks';
|
||||
import { VirtuosoUtil } from '@/lib/virtuoso/Virtuoso.util.tsx';
|
||||
|
||||
export const VirtuosoPersisted = ({
|
||||
ref: passedRef,
|
||||
persistKey,
|
||||
...props
|
||||
}: ComponentProps<typeof Virtuoso> & { persistKey: string }) => {
|
||||
const { state, persistState } = VirtuosoUtil.usePersistState<StateSnapshot>(persistKey);
|
||||
|
||||
const localRef = useRef<VirtuosoHandle>(undefined);
|
||||
const ref = useMergedRef(localRef, passedRef);
|
||||
|
||||
return (
|
||||
<Virtuoso
|
||||
{...props}
|
||||
ref={ref}
|
||||
isScrolling={(isScrolling) => {
|
||||
if (!isScrolling) {
|
||||
localRef.current?.getState(persistState);
|
||||
}
|
||||
|
||||
props.isScrolling?.(isScrolling);
|
||||
}}
|
||||
restoreStateFrom={state}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -6,7 +6,10 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { useCallback, useEffect, useMemo, useRef } from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { useSessionStorage } from '@/modules/core/hooks/useStorage.tsx';
|
||||
import { AppStorage } from '@/lib/storage/AppStorage.ts';
|
||||
|
||||
export class VirtuosoUtil {
|
||||
static readonly GROUP = 0;
|
||||
@@ -112,4 +115,46 @@ export class VirtuosoUtil {
|
||||
[convertIndex, getGroupKey, getNormalKey],
|
||||
);
|
||||
}
|
||||
|
||||
static usePersistState<Snapshot>(key: string): {
|
||||
key: string;
|
||||
state: Snapshot | undefined;
|
||||
persistState: (state: Snapshot) => void;
|
||||
deleteState: () => void;
|
||||
} {
|
||||
const location = useLocation<{ snapshot?: Snapshot }>();
|
||||
|
||||
const snapshotSessionKey = `virtuoso-snapshot-${key}-${location.key}`;
|
||||
const [snapshot] = useSessionStorage<Snapshot | undefined>(snapshotSessionKey, undefined);
|
||||
|
||||
const persistGridStateTimeout = useRef<NodeJS.Timeout | undefined>(undefined);
|
||||
const persistState = useCallback(
|
||||
(state: Snapshot) => {
|
||||
const currentUrl = window.location.href;
|
||||
|
||||
clearTimeout(persistGridStateTimeout.current);
|
||||
persistGridStateTimeout.current = setTimeout(() => {
|
||||
const didLocationChange = currentUrl !== window.location.href;
|
||||
if (didLocationChange) {
|
||||
return;
|
||||
}
|
||||
|
||||
AppStorage.session.setItem(snapshotSessionKey, state, false);
|
||||
}, 250);
|
||||
},
|
||||
[snapshotSessionKey],
|
||||
);
|
||||
const deleteState = useCallback(() => {
|
||||
AppStorage.session.setItem(snapshotSessionKey, undefined, false);
|
||||
}, [snapshotSessionKey]);
|
||||
|
||||
useEffect(() => clearTimeout(persistGridStateTimeout.current), [location.key, persistGridStateTimeout.current]);
|
||||
|
||||
return {
|
||||
key: snapshotSessionKey,
|
||||
state: snapshot,
|
||||
persistState,
|
||||
deleteState,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user