如何解决使用状态快照在Vuex中撤消/重做
上下文
已使用的步骤(概述)
性能问题
-
我已经使用cloneDeep来制作状态的深层副本,因此在替换状态时不保留对当前状态的引用 状态,随着状态变大,cloneDeep需要更多时间 克隆。
-
我使用了一个自定义的replaceState方法,该方法的功能与replaceState完全相同,但是替换模块状态而不是整个应用程序的状态,这最终会花费更长的时间
替换。
由于上述问题,撤消/重做变得迟钝且无法使用。
我很困。我在哪里错了,或者有更好的方法为复杂的状态应用程序实现撤消/重做?
完成:用于撤消并存储状态快照。
撤消:用于重做和存储状态快照。
GlobalStore.js :所有模块组合在一起的全球商店。
export const store = new Vuex.Store({
modules: { canvasEditor,dashboardMetrics }
plugins: [ canvasEditorUndoRedo ]
})
index.js
import { Operations } from ‘./Operations’;
import { actionsToBeUsed } from './constants';
import { cloneDeep } from 'lodash';
export const op = new Operations();
export const canvasEditorUndoRedo = (store) => {
/*
Description: Perform undo/redo operation
Steps:
1.Initalize the class
2.Store the prevIoUs state based on actions
*/
op.init(store);
store.subscribeAction((action,state) => {
if (action.type != 'undo' &&action.type != 'redo' && actionsToBeUsed.find(actionType => actionType == action.type) != undefined) {
// Store the state
let stateClone = cloneDeep(state.canvasEditor);
op.addSnapshot({ id: op.done.length + 1,action,state: stateClone });
}
});
}
Operation.js
import { cloneDeep } from 'lodash';
export class Operations {
store
done=[]
undone = []
init(store) {
this.store = store;
}
addSnapshot(snapshot) {
this.done.push(snapshot);
this.updateOperationsCount();
}
clearUndo() {
this.done = [];
this.updateOperationsCount();
}
clearRedo() {
this.undone = [];
this.updateOperationsCount();
}
undo() {
/*
Description: Performs undo operation based on prevIoUsstate stored in array(done).
Steps:
I. Get the last stored action from array(done) pop it out.
II. Push the undo element(popped element) to redo’s an array (undone).
III. Replace the current state with stored state.
*/
if (this.done.length != 0) {
//I
let undoELement = this.done.pop();
//II
this.undone.push({ id: undoELement.id,action: undoELement.action,state: this.store.state.canvasEditor});
//III
let state = cloneDeep(undoELement.state);
this.replaceCanvasEditorState(state);
this.updateOperationsCount();
}
redo() {
/*
Description: Performs redo operation based on State stored in array(undone).
Steps:
I. Get (pop) the last undo element from undone
II. Push the undo element(popped element) to undo’s an array (done) .
III. Replace the current state with stored state.
*/
if (this.undone.length != 0) {
//I
let redoELement = this.undone.pop();
//II
this.done.push({ id: redoELement.id,action: redoELement.action,state: this.store.state.canvasEditor });
//III
let state = cloneDeep(redoELement.state);
this.replaceCanvasEditorState(state);
this.updateOperationsCount();
}
}
replaceCanvasEditorState(state) {
/*
Description: Replaces current state with state provided as parameter.
*/
this.store._withCommit(() => {
this.store.state.canvasEditor = state;
});
}
updateOperationsCount() {
let undoRedo = {
doneLength: this.done.length,undoneLength: this.undone.length
}
this.store.commit('updateUndoRedoCount',undoRedo);
}
}
CodeSandBox
该应用程序处理许多复杂的操作。
解决方法
恐怕使用快照(深度克隆)在巨大的嵌套状态上执行撤消/重做总是很慢的,更不用说内存消耗了
因此,最好的选择可能是彻底改变策略。当您使用Vuex时,必须使用突变来完成所有更改,因此使用动作/逆向动作策略来实现它应该不难。在每个突变内,不要将状态快照推送到堆栈上,而应在堆栈上推送“反向操作”突变(使用旧的子状态作为参数-如果是对象,则为deepClone
d)。
确保它不像您最初的方法那样透明,并且要求变异作者以特定的方式编写变异,但是您始终可以编写一些帮助程序来使其变得更加容易和“标准化” ...
或者您可以看看undo-redo-vuex Vuex插件,该插件通过保存初始状态和执行的所有变异来实现撤消/重做。当需要撤消时,它将状态重置为初始状态,并重播除最后一个突变以外的所有突变。不知道它的扩展性如何,但至少对突变作者更透明...
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。