优化:修改撤回
This commit is contained in:
65
src/hooks/useUndoRedo.ts
Normal file
65
src/hooks/useUndoRedo.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import { useCallback, useRef, useState } from 'react';
|
||||
|
||||
const MAX_HISTORY = 100;
|
||||
|
||||
function cloneSnapshot<T>(value: T): T {
|
||||
return JSON.parse(JSON.stringify(value)) as T;
|
||||
}
|
||||
|
||||
export function useUndoRedo<T>() {
|
||||
const pastRef = useRef<T[]>([]);
|
||||
const futureRef = useRef<T[]>([]);
|
||||
const [revision, setRevision] = useState(0);
|
||||
|
||||
const bump = useCallback(() => setRevision((n) => n + 1), []);
|
||||
|
||||
const reset = useCallback(() => {
|
||||
pastRef.current = [];
|
||||
futureRef.current = [];
|
||||
bump();
|
||||
}, [bump]);
|
||||
|
||||
const record = useCallback(
|
||||
(previous: T, next: T) => {
|
||||
if (JSON.stringify(previous) === JSON.stringify(next)) return;
|
||||
pastRef.current = [...pastRef.current, cloneSnapshot(previous)].slice(-MAX_HISTORY);
|
||||
futureRef.current = [];
|
||||
bump();
|
||||
},
|
||||
[bump]
|
||||
);
|
||||
|
||||
const undo = useCallback(
|
||||
(current: T): T | null => {
|
||||
if (pastRef.current.length === 0) return null;
|
||||
const previous = pastRef.current[pastRef.current.length - 1];
|
||||
pastRef.current = pastRef.current.slice(0, -1);
|
||||
futureRef.current = [cloneSnapshot(current), ...futureRef.current];
|
||||
bump();
|
||||
return cloneSnapshot(previous);
|
||||
},
|
||||
[bump]
|
||||
);
|
||||
|
||||
const redo = useCallback(
|
||||
(current: T): T | null => {
|
||||
if (futureRef.current.length === 0) return null;
|
||||
const next = futureRef.current[0];
|
||||
futureRef.current = futureRef.current.slice(1);
|
||||
pastRef.current = [...pastRef.current, cloneSnapshot(current)];
|
||||
bump();
|
||||
return cloneSnapshot(next);
|
||||
},
|
||||
[bump]
|
||||
);
|
||||
|
||||
return {
|
||||
revision,
|
||||
canUndo: pastRef.current.length > 0,
|
||||
canRedo: futureRef.current.length > 0,
|
||||
reset,
|
||||
record,
|
||||
undo,
|
||||
redo,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user