撤销重做在编辑需求中应该是很常见的功能了,在 Redux 应用中,全局 store 和 immutable 数据类型,为接入时间旅行功能提供了天然的便利,简单看看吧
设计数据结构
保存一系列应用状态的堆栈,控制保存当前状态的指针,指向其中任何一个状态
const historyState = {
past: [], // 历史状态
current: null, // 当前状态指针
future: [] // 未来状态
}
reducer 函数
实现撤销和恢复操作
const initialState = {
past: [],
current: null,
future: []
}
function undoable(state = initialState, action) {
switch(action.type) {
case 'UNDO':
// 撤销操作
const previous = past[past.length - 1]
const newPast = past.slice(0, past.length - 1)
return {
past: newPast,
current: previous,
future: [current, ...future]
}
case 'REDO':
const next = future[0]
const newFuture = future.slice(1)
return {
past: [...past, current],
current: next,
future: newFuture
}
// 恢复操作
default:
return state;
}
}
整合 redux
通过 reducer enhancer,也叫做高阶 reducer 函数,自动记录信息
function undoableEnhancer(reducer) {
const initialState = {
past: [],
current: reducer(undefined, {}), // 初始化状态
future: []
}
return function undoable(state: initialState, action) {
switch(action.type) {
case 'UNDO':
// 撤销操作
const previous = past[past.length - 1]
const newPast = past.slice(0, past.length - 1)
return {
past: newPast,
current: previous,
future: [current, ...future]
}
case 'REDO':
const next = future[0]
const newFuture = future.slice(1)
return {
past: [...past, current],
current: next,
future: newFuture
}
// 恢复操作
default:
// 代理业务逻辑
const newCurrent = reducer(current, action)
if (current === newCurrent) {
return state
}
return {
past: [...past, current],
current: newCurrent,
future: []
};
}
}
}