Redux是否有一种内置的撤消操作的方法?

Redux是否有一种内置的撤消操作的方法?,redux,Redux,我正在构建一个应用程序,当用户向下滚动时执行操作。如果我能在用户再次向上滚动时撤消这些操作就好了,基本上将滚动变成一种浏览操作时间线的方式 Redux中有内置的方法来实现这一点吗?或者我必须为此编写中间件吗?没有内置的方法。 但是您可以从redux开发工具的工作方式()中得到启发。它基本上具有“时间旅行”功能,它通过跟踪所有动作并每次重新评估来工作。因此,您可以轻松浏览所有更改。我认为,与其说是“撤消”,不如说是在每次操作通过redux时保存对整个状态树的引用 您将拥有一个由不同时间的应用程序状

我正在构建一个应用程序,当用户向下滚动时执行操作。如果我能在用户再次向上滚动时撤消这些操作就好了,基本上将滚动变成一种浏览操作时间线的方式


Redux中有内置的方法来实现这一点吗?或者我必须为此编写中间件吗?

没有内置的方法。
但是您可以从redux开发工具的工作方式()中得到启发。它基本上具有“时间旅行”功能,它通过跟踪所有动作并每次重新评估来工作。因此,您可以轻松浏览所有更改。

我认为,与其说是“撤消”,不如说是在每次操作通过redux时保存对整个状态树的引用

您将拥有一个由不同时间的应用程序状态组成的历史堆栈

let history = [state1, state2, state3]

// some action happens

let history = [state1, state2, state3, state4]

// some action happens

let history = [state1, state2, state3, state4, state5]

// undo an action

let history = [state1, state2, state3, state4]

state = state4
要“撤消”操作,只需将应用程序状态替换为其中一个已保存状态

<>这可以通过支持结构共享的数据结构来实现,但是在开发中,我们并不需要太多地考虑资源约束。 Redux中有内置的方法来实现这一点吗?还是我必须为此编写中间件

在这种情况下,中间件听起来是错误的想法,因为这纯粹是状态管理问题。相反,您可以编写一个函数,该函数接受一个减缩器并返回一个减缩器,通过跟踪操作历史来“增强”它


我在中概述了这种方法,它的工作原理与之类似,只是可以存储操作,而不是存储状态。(取决于你想要做出的权衡,以及能否以不同的顺序“取消”操作是否重要。)

我还想创建一个简单的撤销功能,但已经发布了一个应用程序,可以序列化并加载每个用户的状态。因此,为了保持向后兼容,我不能使用任何包装状态键的解决方案,比如
pass:[]
present:

在寻找替代方案时,激发了我重写
combinereducer
。现在我有了状态的一部分:
history
,它可以保存状态其余部分的10个副本,并在
UNDO
操作中弹出它们。以下是代码,这可能也适用于您的案例:

function shouldSaveUndo(action){
  const blacklist = ['@@INIT', 'REDUX_STORAGE_SAVE', 'REDUX_STORAGE_LOAD', 'UNDO'];

  return !blacklist.includes(action.type);
}

function combineReducers(reducers){
  return (state = {}, action) => {
    if (action.type == "UNDO" && state.history.length > 0){
      // Load previous state and pop the history
      return {
        ...Object.keys(reducers).reduce((stateKeys, key) => {
          stateKeys[key] = state.history[0][key];
          return stateKeys;
        }, {}),
        history: state.history.slice(1)
      }
    } else {
      // Save a new undo unless the action is blacklisted
      const newHistory = shouldSaveUndo(action) ?
        [{
          ...Object.keys(reducers).reduce((stateKeys, key) => {
            stateKeys[key] = state[key];
            return stateKeys;
          }, {})
        }] : undefined;

      return {
        // Calculate the next state
        ...Object.keys(reducers).reduce((stateKeys, key) => {
          stateKeys[key] = reducers[key](state[key], action);
          return stateKeys;
        }, {}),
        history: [
          ...(newHistory || []),
          ...(state.history || [])
        ].slice(0, 10)
      };
    }
  };
}


export default combineReducers({
  reducerOne,
  reducerTwo,
  reducerThree
});

对我来说,这很有魅力,只是看起来不太漂亮。如果这是个好主意/坏主意,我很乐意得到任何反馈,为什么;-)

是的,所以我要写我自己的中间件?是的。我现在在想,我必须编写一个减速机来响应滚动动作来保存当前状态——唯一的问题是,我还不知道如何让减速机同时读取我要保存的状态树部分,然后将其复制到状态树的另一部分。请注意,这不仅仅是为了发展;我的用例是用于实际用户交互的。如果一个reducer需要访问状态树的两个不同部分,这可能意味着您需要一个同时包含这两个部分的reducertogether@Vincent或者,第二种状态实际上不是基本的(即不是真理的来源),可以被抛弃,最后一句话很有意义——如果我保存状态的历史记录,我也应该能够只保留一个指向当前版本的指针(或者只使用堆栈中最新添加的内容)。谢谢我应该补充一点,我使用了这个,并且更详细地描述了我是如何实现它的,这正是我最终要做的——尽管我确实存储了状态。虽然以不同的顺序取消操作并不重要,但在内存方面,存储操作会更好。但是,我不知道如何从我的reducer中再次启动它们-你知道这是怎么做到的吗?@Vincent你不需要再次启动它们,只需通过运行类似于
state.actions.reduce(reducer)
的操作重新计算当前的
,就可以了,谢谢。还有,我刚刚注意到你是雷杜先生;非常感谢这个优秀的图书馆!