实现编辑内容撤销、恢复功能

86 阅读1分钟

实现编辑内容的撤销、恢复功能 (react hook)

useEditHistory.ts

import {useCallback, useState} from 'react';

const useEditHistory = <T>({
    initialHistory,
    onHistoryCurrentChange,
} : {
    /** 初始化数据 */
    initialHistory: T;
    /** 触发当前编辑区域数据变化 */
    onHistoryCurrentChange: (current: T) => void;
}) => {
    const [history, setHistory] = useState<{past: T[]; current: T; future: T[]}>({
        past: [],
        current: [],
        future: []
    });
    
    const resetHistory = useCallback((initialHistory: T) => {
        setHistory({
            past: [],
            current: initialHistory,
            future: [],
        })
    }, []);
    
    const recordHistory = useCallback((current: T) => {
        setHistory(history => {
            if (history.current === current) return history;
            return {
                past: [...history.past, history.current],
                current,
                future: [],
            }
        })
    }, []);
    
    // 撤销
    const undo = useCallback((current: T) => {
        setHistory(history => {
            if (!history.past.length) return history;
            const current = history.past[history.past.length - 1];
            onHistoryCurrentChange(current);
            
            return {
                past: history.past.slice(0, -1),
                current,
                future: [...history.future, history.current],
            };
        });
    }, [onHistoryCurrentChange]);
    
    // 恢复
    const redo = useCallback((current: T) => {
        setHistory(history => {
            if (!history.future.length) return history;
            const current = history.future[history.future.length - 1];
            onHistoryCurrentChange(current);
            
            return {
                past: [...history.past, history.current],
                current,
                future: history.future.slice(0, -1),
            };
        });
    }, [onHistoryCurrentChange]);
    
    return {resetHistory, recordHistory, history, setHistory, undo, redo};
}

export default useEditHistory;