Redux 是否有内置的方法来撤消操作?
Does Redux have a built-in way to undo actions?
我正在构建一个应用程序,用户向下滚动时会执行操作。如果我可以在用户再次向上滚动时撤消这些操作,那就太好了,基本上将滚动变成一种浏览操作时间线的方式。
Redux 中是否有内置的方法来执行此操作?或者我必须为此编写中间件吗?
没有执行此操作的内置方法。
但您可以从 redux-dev-tools 的工作原理中获得灵感 (https://github.com/gaearon/redux-devtools)。它基本上具有 "time travel" 功能,并且通过跟踪所有操作并每次重新评估它们来工作。因此,您可以轻松浏览所有更改。
我认为这个想法与其说是"undo",不如说是在每次动作通过 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
对于 "undo" 一个动作,您只需将应用程序状态替换为其中一个保存的状态。
这可以通过支持结构共享的数据结构变得高效,但在开发中我们真的不需要过多考虑资源限制。
Is there a built-in way in Redux to do this? Or would I have to write middleware for this?
在这种情况下,中间件听起来像是错误的想法,因为这纯粹是状态管理问题。相反,您可以编写一个函数,它接受一个 reducer 和 returns 一个 reducer,并在整个过程中通过操作历史跟踪来“增强”它。
我在 this answer, and it's similar to how redux-undo 作品中概述了这种方法,不同之处在于您可以存储操作而不是存储状态。 (取决于您要做出的权衡,以及能够以与发生顺序不同的顺序“取消”操作是否重要。)
我也想创建一个简单的撤消功能,但已经发布了一个带有 redux-storage that serializes and loads the state for every user. So to keep it backwards-compatible, I couldn't use any solution that wraps my state keys, like redux-undo 的应用程序与 past: []
和 present:
。
寻找替代方案,Dan's tutorial 启发我改写 combineReducers
。现在我有状态的一部分: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
});
对我来说,这就像一个魅力,只是看起来不太漂亮。如果这是个好主意/坏主意以及原因,我会很高兴收到任何反馈 ;-)
我正在构建一个应用程序,用户向下滚动时会执行操作。如果我可以在用户再次向上滚动时撤消这些操作,那就太好了,基本上将滚动变成一种浏览操作时间线的方式。
Redux 中是否有内置的方法来执行此操作?或者我必须为此编写中间件吗?
没有执行此操作的内置方法。 但您可以从 redux-dev-tools 的工作原理中获得灵感 (https://github.com/gaearon/redux-devtools)。它基本上具有 "time travel" 功能,并且通过跟踪所有操作并每次重新评估它们来工作。因此,您可以轻松浏览所有更改。
我认为这个想法与其说是"undo",不如说是在每次动作通过 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
对于 "undo" 一个动作,您只需将应用程序状态替换为其中一个保存的状态。
这可以通过支持结构共享的数据结构变得高效,但在开发中我们真的不需要过多考虑资源限制。
Is there a built-in way in Redux to do this? Or would I have to write middleware for this?
在这种情况下,中间件听起来像是错误的想法,因为这纯粹是状态管理问题。相反,您可以编写一个函数,它接受一个 reducer 和 returns 一个 reducer,并在整个过程中通过操作历史跟踪来“增强”它。
我在 this answer, and it's similar to how redux-undo 作品中概述了这种方法,不同之处在于您可以存储操作而不是存储状态。 (取决于您要做出的权衡,以及能够以与发生顺序不同的顺序“取消”操作是否重要。)
我也想创建一个简单的撤消功能,但已经发布了一个带有 redux-storage that serializes and loads the state for every user. So to keep it backwards-compatible, I couldn't use any solution that wraps my state keys, like redux-undo 的应用程序与 past: []
和 present:
。
寻找替代方案,Dan's tutorial 启发我改写 combineReducers
。现在我有状态的一部分: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
});
对我来说,这就像一个魅力,只是看起来不太漂亮。如果这是个好主意/坏主意以及原因,我会很高兴收到任何反馈 ;-)