【问题标题】:What is the best way to implement undo state change (undo store/history implementation) in React Redux在 React Redux 中实现撤消状态更改(撤消存储/历史实现)的最佳方式是什么
【发布时间】:2017-03-28 05:03:06
【问题描述】:

我正在寻找 redux react 应用程序中的历史重做/存储重置为先前状态

我发现了一个blog 告诉它可以通过将当前、未来和过去的状态存储在堆栈中并相应地重置来完成。

我还在 StackOverflow 中找到了类似的 question,但它没有给我正确的答案,或者我可能很难理解。

我已经构建了一个演示 ToDo app 并使用 redux-logger 来记录包含先前状态和更新状态的存储详细信息。你可以在这里找到code

我们在 redux 中是否有一个 store reset 方法,以便我们可以获取以前的状态并更新 store 其他有现在、过去和未来状态的 store?

【问题讨论】:

    标签: javascript reactjs redux react-redux


    【解决方案1】:

    适用于在 2020 年寻找解决方案的任何人。您不必将整个状态对象存储为现在、过去和未来。

    相反,您可以只存储有关已更改内容的详细信息。这可以使用ImmerJS 来实现。它记录对状态对象所做的所有更改并生成称为补丁的东西。

    示例:如果age32更新为40,那么生成的补丁将是:

    补丁: [ { op: 'replace', path: [ 'age' ], value: 40 } ]

    反向补丁: [ { op: 'replace', path: [ 'age' ], value: 32 } ]

    它还公开了一种将这些补丁/反向补丁应用于状态的方法 - applyPatch。因此,要撤消,我们可以应用反向补丁,而要重做,我们可以应用补丁。

    您可以在此处找到完整实施的详细信息:Implementing Undo-Redo Functionality in Redux using Immer

    【讨论】:

      【解决方案2】:

      什么是最好的方法...

      最佳方式总是难以定义,它实际上取决于您的用例和需求,包括客户端和服务器。

      但要开始,您可以考虑使用库或查看他们如何解决此问题,例如:

      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];
      

      【讨论】:

      • 所以我相信存储以前的状态是唯一的方法,如下所示。 { 过去:[...pastStatesHere...],现在:{...currentStateHere...},未来:[...futureStatesHere...] }
      • 存储状态是一种常见的方式,但您可以探索不同的场景,例如使用称为命令模式的设计模式(即使我认为在 redux 中没有必要)。
      • @sudheeshcm 如果您发现我的答案有用,请考虑使用此答案左侧的图标接受/投票。谢谢! :)
      • 这些例子很有帮助。我赞成你的回答。如果我可以再等一会儿,这样其他人可以补充他们的观点,那就太好了。谢谢。
      • 这里的浏览量好像不多。我会接受你的回答。其他的请分享你的观点,如果有的话。我们仍然可以对新答案进行投票。 ;) 谢谢。
      【解决方案3】:

      我创建了一个状态撤消/重做快照管理器类,它非常适合跟踪 HTML 元素的更改历史记录。

        <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>
      

      查看这个 JSFiddle:https://jsfiddle.net/up73q4t0/56/

      【讨论】:

        猜你喜欢
        • 2010-09-17
        • 2016-02-18
        • 2021-02-28
        • 2013-01-22
        • 2017-08-30
        • 2012-05-20
        • 2022-12-16
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多