Better

Ethan的博客,欢迎访问交流

使用 Redux 实现时间旅行

撤销重做在编辑需求中应该是很常见的功能了,在 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: []
      };
  }
  }
}


留言