我已经实现了一种相当简单的方法,可以通过以下操作将撤消添加到useReducer
:
export const stateMiddleware = reducerFunc => {
return function(state = { history: [] }, action) {
return {
history:
action.type === UNDO
? drop(state.history) // lodash drop
: [reducerFunc(state.history[0], action), ...state.history],
}
}
}
和
const [state, dispatch] = useReducer(stateMiddleware(reducer), { history: [initialState] })
state
变量包含整个历史记录,因此必须从第一个元素中提取当前状态。
我想知道useReducer
是否会接受state
参数的数组(并且也欢迎对我的方法发表评论-它避免使用似乎笨重的程序包执行类似的操作)< / p>
答案 0 :(得分:1)
为了给您一些有关通用方法的反馈,我将引用Redux文档,因为它们提供了许多有关全局状态管理的最佳实践。如果您以后需要一个完整的存储,则它使切换更加容易。我在这里假设您不仅要使用useReducer
来用于一个本地组件,而且要使用一个更全局的状态树(感谢@DrewReese对此发表评论)。如果只有一个组件左右,那么您的方法就可以了!
有关基本状态形状的Redux文档,以及在顶层(Link)上是否可以使用数组:
Redux状态通常具有一个纯Javascript对象作为状态树的顶部。 (当然也可以使用另一种类型的数据,例如单个数字,数组或特殊的数据结构,但是大多数库都假定顶级值是一个普通对象。)最常见的组织方式该顶级对象中的数据是将数据进一步分为子树,其中每个顶级键代表相关数据的某些“域”或“切片”。
所以基本上可以,但是其他库也可能会被优化并期望有一个对象,因为到目前为止这是最可能的选择。
如果您采用这种形状,请确保您的 whole 状态始终 需要撤消操作。因为这是有代价的(除了提到的第3方lib兼容性之外):
如果您的应用程序变得非常庞大,并且您有数百个减速器,那该怎么办?每次调度您的操作时,都会在history数组中放置一个新的状态对象,这可能会造成混乱。 如果您不希望全局撤消,而是一个非常精细的撤消(在一个特定的reducer中,例如针对UI中的一个特定表单元素),该怎么办?然后,您必须区分全局撤消和特定撤消。可以只在每个感兴趣的减速器中以自己的方式处理的一个“ UNDO”动作又如何呢?
如果仍然符合您的要求,请尝试一下!
欢呼
答案 1 :(得分:1)
答案 2 :(得分:0)
这是有可能的,但是正如ford04指出的那样,出于各种原因,它可能不是一个好主意。
下面的演示显示了如何使用普通数组作为state
中的useReducer
。
const initialState = [];
function reducer(state, action) {
switch (action.type) {
case 'increment':
return [...state, state.length + 1];
case 'decrement':
return [...state.slice(0, -1)];
default:
throw new Error();
}
}
function Counter() {
const [state, dispatch] = React.useReducer(reducer, initialState);
return (
<React.Fragment>
<div>
State: {state.join()}
</div>
<button onClick={() => dispatch({type: 'increment'})}>+</button>
<button onClick={() => dispatch({type: 'decrement'})}>-</button>
</React.Fragment>
);
}
ReactDOM.render(<Counter />, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>
<div id="app"></div>