Ash*_*son 15 javascript undo-redo reactjs redux
有一段时间,我一直在讨论如何在Redux中使用服务器交互(通过ajax)实现undo/redo .
我已经提出了一个使用命令模式的解决方案,其中操作使用execute
和undo
方法作为命令注册,而不是调度操作您调度命令.然后将命令存储在堆栈中并在需要时引发新操作.
我当前的实现使用中间件拦截调度,测试命令和调用Command的方法,看起来像这样:
let commands = [];
function undoMiddleware({ dispatch, getState }) {
return function (next) {
return function (action) {
if (action instanceof Command) {
// Execute the command
const promise = action.execute(action.value);
commands.push(action);
return promise(dispatch, getState);
} else {
if (action.type === UNDO) {
// Call the previous commands undo method
const command = commands.pop();
const promise = command.undo(command.value);
return promise(dispatch, getState);
} else {
return next(action);
}
}
};
};
}
Run Code Online (Sandbox Code Playgroud)
const UNDO = 'UNDO';
function undo() {
return {
type: UNDO
}
}
function add(value) {
return (dispatch, getState) => {
const { counter } = getState();
const newValue = counter + value;
return new Promise((resolve, reject) => {
resolve(newValue); // Ajax call goes here
}).then((data) => {
dispatch(receiveUpdate(data));
});
}
}
function sub(value) {
return (dispatch, getState) => {
const { counter } = getState();
const newValue = counter - value;
return new Promise((resolve, reject) => {
resolve(newValue); // Ajax call goes here
}).then((data) => {
dispatch(receiveUpdate(data));
});
}
}
Run Code Online (Sandbox Code Playgroud)
class Command {
execute() {
throw new Error('Not Implemented');
}
undo() {
throw new Error('Not Implemented');
}
}
class AddCommand extends Command {
constructor(value) {
super();
this.value = value;
}
execute() {
return add(this.value);
}
undo() {
return sub(this.value);
}
}
Run Code Online (Sandbox Code Playgroud)
const store = createStoreWithMiddleware(appReducer);
store.dispatch(new AddCommand(10)); // counter = 10
store.dispatch(new AddCommand(5)); // counter = 15
// Some time later
store.dispatch(undo()); // counter = 10
Run Code Online (Sandbox Code Playgroud)
(这里有一个更完整的例子)
我目前采用的方法有几个问题:
UNDO
命令类型.那么我的问题是,是否有人可以建议在Redux中实现此功能的更好方法?
我现在看到的最大缺陷是在动作完成之前添加的命令,以及如何在混合中添加乐观更新.
任何见解都表示赞赏.
不确定我完全理解你的用例,但在我看来,在 ReactJS 中实现撤消/重做的最佳方法是通过不可变模型。一旦你的模型是不可变的,你就可以在状态发生变化时轻松维护状态列表。具体来说,您需要一个撤消列表和一个重做列表。在你的例子中,它会是这样的:
第一个列表中的最后一个值是当前状态(进入组件状态)。
这是比命令更简单的方法,因为您不需要为要执行的每个操作单独定义撤消/重做逻辑。
如果您需要与服务器同步状态,您也可以这样做,只需将 AJAX 请求作为撤消/重做操作的一部分发送即可。
乐观更新也应该是可能的,您可以立即更新您的状态,然后发送您的请求并在其错误处理程序中恢复到更改之前的状态。就像是:
var newState = ...;
var previousState = undoList[undoList.length - 1]
undoList.push(newState);
post('server.com', buildServerRequestFrom(newState), onSuccess, err => { while(undoList[undoList.length-1] !== previousState) undoList.pop() };
Run Code Online (Sandbox Code Playgroud)
事实上,我相信您应该能够通过这种方法实现您列出的所有目标。如果您有不同的感觉,您能否更具体地说明您需要做什么?
归档时间: |
|
查看次数: |
4413 次 |
最近记录: |