useReducer 可以使用状态数组吗?
Can useReducer work with an array for state?
我已经实现了一种相当简单的方法来向 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
参数的数组(也欢迎对我的方法发表评论 - 它避免使用看似庞大的包来做类似的事情)
为了给你一些关于你的一般方法的反馈,我将引用 Redux 文档,因为它们提供了许多关于全局状态管理的最佳实践。如果您以后需要一家成熟的商店,它会使切换更容易。我在这里假设您不仅要将 useReducer
用于一个本地组件,还要用于一个更全局的状态树(感谢@DrewReese 对此发表评论)。如果它只是关于一个组件左右,你的方法完全没问题!
关于基本状态形状的 Redux 文档以及是否可以在顶层使用数组 (Link):
A Redux state usually has a plain Javascript object as the top of the state tree. (It is certainly possible to have another type of data instead, such as a single number, an array, or a specialized data structure, but most libraries assume that the top-level value is a plain object.) The most common way to organize data within that top-level object is to further divide data into sub-trees, where each top-level key represents some "domain" or "slice" of related data.
所以基本上,它没问题,但其他库可能会有意见并期待一个对象,因为它是迄今为止最有可能的选择。
如果您实施此形状,请确保您的要求是始终需要对您的整个状态执行撤消操作。因为它是有代价的(除了提到的第 3 方库兼容性之外):
- 直接在顶层添加一层额外的嵌套
- 可扩展性和粒度(见下一点)
什么,如果您的应用程序变得非常庞大并且您有数百个减速器。每次调度您的操作时,历史数组中都会放入一个新的状态对象,这可能会变得混乱。
什么,如果您不想要全局撤消,而是非常细粒度的撤消(在一个特定的 reducer 中,比如 UI 中的一个特定表单元素)。那么您将必须区分全局撤消和特定撤消。如果只有一个 "UNDO" 操作可以在每个感兴趣的 reducer 中以自己的方式处理呢?
如果仍然符合您的要求,请尝试一下!
干杯
如果您真正想问的是是否可以使用普通数组初始化 useReducer
挂钩状态,那么可以。
可能,但正如 ford04 指出的那样,出于各种原因,这可能不是一个好主意。
下面的演示显示它可以使用普通数组作为 useReducer
中的 state
。
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>
我已经实现了一种相当简单的方法来向 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
参数的数组(也欢迎对我的方法发表评论 - 它避免使用看似庞大的包来做类似的事情)
为了给你一些关于你的一般方法的反馈,我将引用 Redux 文档,因为它们提供了许多关于全局状态管理的最佳实践。如果您以后需要一家成熟的商店,它会使切换更容易。我在这里假设您不仅要将 useReducer
用于一个本地组件,还要用于一个更全局的状态树(感谢@DrewReese 对此发表评论)。如果它只是关于一个组件左右,你的方法完全没问题!
关于基本状态形状的 Redux 文档以及是否可以在顶层使用数组 (Link):
A Redux state usually has a plain Javascript object as the top of the state tree. (It is certainly possible to have another type of data instead, such as a single number, an array, or a specialized data structure, but most libraries assume that the top-level value is a plain object.) The most common way to organize data within that top-level object is to further divide data into sub-trees, where each top-level key represents some "domain" or "slice" of related data.
所以基本上,它没问题,但其他库可能会有意见并期待一个对象,因为它是迄今为止最有可能的选择。
如果您实施此形状,请确保您的要求是始终需要对您的整个状态执行撤消操作。因为它是有代价的(除了提到的第 3 方库兼容性之外):
- 直接在顶层添加一层额外的嵌套
- 可扩展性和粒度(见下一点)
什么,如果您的应用程序变得非常庞大并且您有数百个减速器。每次调度您的操作时,历史数组中都会放入一个新的状态对象,这可能会变得混乱。 什么,如果您不想要全局撤消,而是非常细粒度的撤消(在一个特定的 reducer 中,比如 UI 中的一个特定表单元素)。那么您将必须区分全局撤消和特定撤消。如果只有一个 "UNDO" 操作可以在每个感兴趣的 reducer 中以自己的方式处理呢?
如果仍然符合您的要求,请尝试一下!
干杯
如果您真正想问的是是否可以使用普通数组初始化 useReducer
挂钩状态,那么可以。
可能,但正如 ford04 指出的那样,出于各种原因,这可能不是一个好主意。
下面的演示显示它可以使用普通数组作为 useReducer
中的 state
。
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>