我正在 redux react 应用程序中寻找历史重做/存储重置为之前的状态。
我发现blog告诉它可以通过将当前,未来和过去状态存储在堆栈中并相应地重置来完成。
我也在 StackOverflow 中找到了类似的question,但它没有给我一个正确的答案,也许我很难理解。
我已经构建了一个演示ToDo app,并使用 redux-logger 来记录先前状态和更新状态的商店详细信息。你可以在这里找到code。
我们在redux中是否有商店重置方法,以便我们可以获得以前的状态并更新具有当前,过去和未来状态的商店的商店?
答案 0 :(得分:5)
最好的方法是什么......
最好的方法总是难以定义,它实际上取决于您的用例和客户端和服务器的要求。
但是要开始你,你可以考虑使用一个库或者看看他们如何处理这个问题,例如:
https://github.com/omniscientjs/immstruct
https://www.npmjs.com/package/redux-undo
https://github.com/PowToon/redux-undo-redo
在redux中使用todo undo / redo的示例教程: https://github.com/reactjs/redux/tree/master/examples/todos-with-undo
或者您可以实现自己的,因为redux可以存储您的所有应用程序状态。简单的堆栈可以是在任何给定时间存储应用状态的简单而有效的方式。
let yourHistory = [state1, state2, state3];
答案 1 :(得分:4)
对于任何在2020年寻求解决方案的人。您不必将整个状态对象存储为现在,过去和将来。
相反,您可以只存储有关已更改内容的详细信息。可以使用ImmerJS来实现。它记录对状态对象所做的所有更改,并生成称为补丁的内容。
示例:如果将age
从32
更新为40
,则生成的补丁将是:
补丁程序:
[ { op: 'replace', path: [ 'age' ], value: 40 } ]
反补丁: [ { op: 'replace', path: [ 'age' ], value: 32 } ]
它还公开了将这些补丁/反补丁应用于状态applyPatch
的方法。因此,要撤消,我们可以应用反向补丁,而要重做,我们可以应用补丁。
您可以在此处找到完整实施的详细信息:Implementing Undo-Redo Functionality in Redux using Immer
答案 2 :(得分:0)
I created a state undo/redo snapshot manager class, which would be great for tracking the change history on an HTML element.
<div id="buttons">
<button type="button" id="undo_btn">Undo</button>
<button type="button" id="redo_btn">Redo</button>
</div>
<br/><br/>
<div id="content">
<label>
Input1:
<input type="text" value="" />
</label>
<br/><br/>
<label>
Input2:
<input type="text" value="" />
</label>
<br/><br/>
<label>
Input3:
<input type="text" value="" />
</label>
<br/><br/>
<label>
Input4:
<input type="text" value="" />
</label>
<br/><br/>
</div>
<script type="text/javascript">
var StateUndoRedo = function() {
var init = function(opts) {
var self = this;
self.opts = opts;
if(typeof(self.opts['undo_disabled']) == 'undefined') {
self.opts['undo_disabled'] = function() {};
}
if(typeof(self.opts['undo_enabled']) == 'undefined') {
self.opts['undo_enabled'] = function() {};
}
if(typeof(self.opts['redo_disabled']) == 'undefined') {
self.opts['redo_disabled'] = function() {};
}
if(typeof(self.opts['redo_enabled']) == 'undefined') {
self.opts['redo_enabled'] = function() {};
}
if(typeof(self.opts['restore']) == 'undefined') {
self.opts['restore'] = function() {};
}
self.opts['undo_disabled']();
self.opts['redo_disabled']();
}
var add = function(state) {
var self = this;
if(typeof(self.states) == 'undefined') {
self.states = [];
}
if(typeof(self.state_index) == 'undefined') {
self.state_index = -1;
}
self.state_index++;
self.states[self.state_index] = state;
self.states.length = self.state_index + 1;
if(self.state_index > 0) {
self.opts['undo_enabled']();
}
self.opts['redo_disabled']();
}
var undo = function() {
var self = this;
if(self.state_index > 0) {
self.state_index--;
if(self.state_index == 0) {
self.opts['undo_disabled']();
} else {
self.opts['undo_enabled']();
}
self.opts['redo_enabled']();
self.opts['restore'](self.states[self.state_index]);
}
}
var redo = function() {
var self = this;
if(self.state_index < self.states.length) {
self.state_index++;
if(self.state_index == self.states.length - 1) {
self.opts['redo_disabled']();
} else {
self.opts['redo_enabled']();
}
self.opts['undo_enabled']();
self.opts['restore'](self.states[self.state_index]);
}
}
var restore = function() {
var self = this;
self.opts['restore'](self.states[self.state_index]);
}
var clear = function() {
var self = this;
self.state_index = 0;
//self.states = [];
}
return {
init: init,
add: add,
undo: undo,
redo: redo,
restore: restore,
clear: clear
};
};
//initialize object
var o = new StateUndoRedo();
o.init({
'undo_disabled': function() {
//make the undo button hidden
document.getElementById("undo_btn").disabled = true;
},
'undo_enabled': function() {
//make the undo button visible
document.getElementById("undo_btn").disabled = false;
},
'redo_disabled': function() {
//make the redo button hidden
document.getElementById("redo_btn").disabled = true;
},
'redo_enabled': function() {
//make the redo button visible
document.getElementById("redo_btn").disabled = false;
},
'restore': function(state) {
//replace the current content with the restored state content
document.getElementById("content").innerHTML = state;
}
});
//initialize first state
o.add(document.getElementById("content").innerHTML);
o.restore();
o.clear();
//bind click events for undo/redo buttons
document.getElementById("undo_btn").addEventListener("click", function() {
o.undo();
});
document.getElementById("redo_btn").addEventListener("click", function() {
o.redo();
});
//bind change events for content element
document.getElementById('content').addEventListener("change", function(event) {
// the following is required since vanilla JS innerHTML
// does not capture user-changed values of inputs
// so we set the attributes explicitly (use jQuery to avoid this)
var elems = document.querySelectorAll("#content input");
for(var i = 0; i < elems.length; i++) {
elems[i].setAttribute("value", elems[i].value);
}
//take a snapshot of the current state of the content element
o.add(document.getElementById("content").innerHTML);
});
</script>
See this JSFiddle: https://jsfiddle.net/up73q4t0/56/