使用redux-undo实现撤销重做功能

使用redux-undo实现撤销重做功能

实现效果

使用redux-undo实现撤销重做功能_第1张图片

安装依赖

redux-undo 文档

yarn add redux-undo

包装 Reducer

undoable 包装你的原始 reducer,使其支持历史记录功能。

import { configureStore } from '@reduxjs/toolkit'
import counterReducer from './counterSlice'
import userInfoReducer from './userInfoSlice'
import componentReducer from './componentsReducer'
import pageInfoReducer from './pageInfoReducer'
import undoable, { excludeAction } from 'redux-undo'

const store = configureStore({
  reducer: {
    counter: counterReducer,
    userInfo: userInfoReducer,
    pageInfo: pageInfoReducer,
    // 使用undoable包裹想要实现撤回的reduce
    components: undoable(componentReducer, {
      // 限制历史记录最多 20 步
      limit: 20,
      // 过滤不需要记录的操作(如选中组件)
      filter: excludeAction([
        'components/changeSelectedId',
        'components/selectPrevComponent',
        'components/selectNextComponent',
        'components/resertComponents'
      ]),
      // 自定义undo类型,防止和其他的reduce冲突
      undoType: 'ComponentUndo',
      redoType: 'ComponentRedo'
    })
  }
})

type GetStateFunType = typeof store.getState

export type RootState = ReturnType<GetStateFunType> // 定义TS类型,使用时出现提示

export default store

修改原来的导入方式,从 present 中导出数据

import { useSelector } from 'react-redux'
import { RootState } from '../store'
import { componentInfoType } from '../store/componentsReducer'

function useGetComponentInfo() {
  const components = useSelector((state: RootState) => state.components.present)

  const { componentsList = [], selectedId, copiedComponent } = components

  const getSelectedComponent = () => {
    if (!selectedId) {
      return {}
    }
    return componentsList.find(c => c._id === selectedId) || {}
  }

  return {
    // 当前画布中的所有组件
    componentsList,
    // 当前选中的组件id
    selectedId,
    // 当前被复制的组件信息
    copiedComponent,
    // 获取当前选中的组件配置
    selectedComponent: getSelectedComponent() as componentInfoType
  }
}

export default useGetComponentInfo

添加撤回和重做按钮

import { Space, Tooltip, Button } from 'antd'
import {
  UndoOutlined,
  RedoOutlined
} from '@ant-design/icons'
import React from 'react'
import { useDispatch } from 'react-redux'
import { useKeyPress } from 'ahooks'

export default function EditToolbar() {
  const dispatch = useDispatch()

  function undo() {
    dispatch({
      type: 'ComponentUndo'
    })
  }

  function redo() {
    dispatch({
      type: 'ComponentRedo'
    })
  }

  // 给画布绑定键盘事件
  function useBindCanvansKeyPress() {
    // 撤回
    useKeyPress(['ctrl.z', 'meta.z'], () => {
      undo()
    })
    // 重做
    useKeyPress(['ctrl.y', 'meta.y'], () => {
      redo()
    })
  }

  useBindCanvansKeyPress()

  return (
    <Space>
      {/* 省略其他代码 */}
          
      <Tooltip title="撤回">
        <Button shape="circle" icon={<UndoOutlined />} onClick={undo} />
      </Tooltip>

      <Tooltip title="重做">
        <Button shape="circle" icon={<RedoOutlined />} onClick={redo} />
      </Tooltip>
    </Space>
  )
}

你可能感兴趣的:(react.js,前端框架)