import React, { createContext, useContext, useState, useCallback, useRef, useEffect } from 'react'; import { Node, Edge } from '@xyflow/react'; interface HistoryContextType { undo: () => void; redo: () => void; canUndo: boolean; canRedo: boolean; takeSnapshot: () => void; } const HistoryContext = createContext(undefined); export const useHistory = () => { const context = useContext(HistoryContext); if (!context) { throw new Error('useHistory must be used within a HistoryProvider'); } return context; }; interface HistoryProviderProps { children: React.ReactNode; initialNodes: Node[]; initialEdges: Edge[]; onHistoryChange: (nodes: Node[], edges: Edge[]) => void; } const HistoryProvider: React.FC = ({ children, initialNodes, initialEdges, onHistoryChange }) => { // 历史记录状态 const [history, setHistory] = useState<{ nodes: Node[]; edges: Edge[] }[]>([ { nodes: initialNodes, edges: initialEdges } ]); const [step, setStep] = useState(0); // 当前状态的引用,避免重复添加相同状态 const currentState = useRef({ nodes: initialNodes, edges: initialEdges }); // 检查两个状态是否相等 const isSameState = useCallback((state1: { nodes: Node[]; edges: Edge[] }, state2: { nodes: Node[]; edges: Edge[] }) => { // 只比较节点和边的关键属性,忽略拖动过程中的临时状态 if (state1.nodes.length !== state2.nodes.length || state1.edges.length !== state2.edges.length) { return false; } // 比较节点 for (let i = 0; i < state1.nodes.length; i++) { const node1 = state1.nodes[i]; const node2 = state2.nodes[i]; if (node1.id !== node2.id || node1.type !== node2.type || node1.position.x !== node2.position.x || node1.position.y !== node2.position.y || JSON.stringify(node1.data) !== JSON.stringify(node2.data)) { return false; } } // 比较边 for (let i = 0; i < state1.edges.length; i++) { const edge1 = state1.edges[i]; const edge2 = state2.edges[i]; if (edge1.id !== edge2.id || edge1.source !== edge2.source || edge1.target !== edge2.target || edge1.sourceHandle !== edge2.sourceHandle || edge1.targetHandle !== edge2.targetHandle) { return false; } } return true; }, []); // 拍摄快照 const takeSnapshot = useCallback(() => { // 获取当前状态 const { nodes, edges } = currentState.current; // 如果当前状态与历史记录中的当前步骤相同,则不添加新快照 const currentHistoryState = history[step]; if (isSameState({ nodes, edges }, currentHistoryState)) { return; } // 删除当前步骤之后的所有历史记录 const newHistory = history.slice(0, step + 1); // 添加新快照 newHistory.push({ nodes: nodes.map(node => ({ ...node })), edges: edges.map(edge => ({ ...edge })) }); // 限制历史记录长度,防止内存泄漏 const maxLength = 100; if (newHistory.length > maxLength) { newHistory.shift(); setStep(prev => prev - 1); } setHistory(newHistory); setStep(newHistory.length - 1); }, [history, step, isSameState]); // 撤销操作 const undo = useCallback(() => { if (step <= 0) return; const prevStep = step - 1; const { nodes, edges } = history[prevStep]; currentState.current = { nodes, edges }; setStep(prevStep); onHistoryChange([...nodes], [...edges]); }, [step, history, onHistoryChange]); // 重做操作 const redo = useCallback(() => { if (step >= history.length - 1) return; const nextStep = step + 1; const { nodes, edges } = history[nextStep]; currentState.current = { nodes, edges }; setStep(nextStep); onHistoryChange([...nodes], [...edges]); }, [step, history, onHistoryChange]); // 更新当前状态的引用 const updateCurrentState = useCallback((nodes: Node[], edges: Edge[]) => { currentState.current = { nodes, edges }; }, []); // 监听 takeSnapshot 事件 useEffect(() => { const handleTakeSnapshot = ((event: CustomEvent) => { const { nodes, edges } = event.detail; updateCurrentState(nodes, edges); takeSnapshot(); }) as EventListener; document.addEventListener('takeSnapshot', handleTakeSnapshot); return () => { document.removeEventListener('takeSnapshot', handleTakeSnapshot); }; }, [takeSnapshot, updateCurrentState]); const value = { undo, redo, canUndo: step > 0, canRedo: step < history.length - 1, takeSnapshot }; return ( {children} ); }; export default HistoryProvider;