Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | 1x 1x 1x 1x 1x 11x 11x 11x 11x 11x 11x 10x 10x 10x 11x 1x 1x 1x 1x 11x 11x 11x 11x 10x 10x 10x 9x 9x 9x 9x 10x 10x 11x 11x 11x | import { history, type HistoryOptions, type HistoryState, softEqual, type State } from '@anchorlib/core';
import { useEffect, useMemo, useRef } from 'react';
import { CLEANUP_DEBOUNCE_TIME } from './constant.js';
import { useMicrotask } from './hooks.js';
export type HistoryRef = {
history: HistoryState;
options?: HistoryOptions;
};
/**
* A React hook that provides history management for a given state.
*
* @template T - The type of the state extending from State
* @param state - The initial state to track history for
* @param options - Optional history configuration options
* @returns The history state object containing current state, history methods, and navigation functions
*/
export function useHistory<T extends State>(state: T, options?: HistoryOptions): HistoryState {
const [cleanup, cancelCleanup] = useMicrotask(CLEANUP_DEBOUNCE_TIME);
// Create reference map to hold the history states that being used in the current component.
const historyRef = useRef(new Map<State, HistoryRef>()).current;
// Create reference to hold the active history state.
const currentRef = useRef<HistoryState>(null);
// Use memo to create or switch between history states when the state or options changes.
const historyState = useMemo(() => {
let current = historyRef.get(state) as HistoryRef;
if (!current) {
// Initialize new history state if the state is not in the reference map.
const newHistory = history(state, options);
current = { history: newHistory, options };
historyRef.set(state, current);
} else if (options && !softEqual(options, current.options)) {
// Cleanup the existing history state if the options have changed before re-creating.
current.history.destroy();
// Re-create the history state if the options have changed.
current.history = history(state, options);
current.options = options;
}
currentRef.current = current.history;
return currentRef.current;
}, [state, options]);
useEffect(() => {
// Prevent cleanup if the component is unmounted and remounted quickly (e.g., in Strict Mode).
cancelCleanup();
return () => {
// Cleanup the history when the component is truly unmounted.
cleanup(() => {
for (const ref of historyRef.values()) {
ref.history.destroy();
}
historyRef.clear();
});
};
}, []);
return historyState;
}
|