admin管理员组文章数量:1327969
I've implemented a fairly simple means to add undo to useReducer
with the following:
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],
}
}
}
and
const [state, dispatch] = useReducer(stateMiddleware(reducer), { history: [initialState] })
The state
variable consists of the entire history so present state will have to be extracted from the first element.
I'm wondering whether useReducer
will accept an array for the state
parameter (and also wele to ments on my approach - it avoids using what seem to be hefty packages to do something similar)
I've implemented a fairly simple means to add undo to useReducer
with the following:
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],
}
}
}
and
const [state, dispatch] = useReducer(stateMiddleware(reducer), { history: [initialState] })
The state
variable consists of the entire history so present state will have to be extracted from the first element.
I'm wondering whether useReducer
will accept an array for the state
parameter (and also wele to ments on my approach - it avoids using what seem to be hefty packages to do something similar)
3 Answers
Reset to default 3If all you are really asking is if you can initialize useReducer
hook state with a plain array, then yes, you can.
Example:
const reducer = (state, action) => {
switch (action.type) {
....
}
};
function App() {
const [state, dispatch] = useReducer(
reducer,
[] // <-- initial array value
);
return (
<div className="App">
<div>State: {JSON.stringify(state)}</div>
<button
onClick={() =>
dispatch({ type: "add", data: Math.floor(Math.random() * 10) })
}
>
+
</button>
<button onClick={() => dispatch({ type: "remove" })}>-</button>
</div>
);
}
To give you some feedback on your general approach, I'll quote the Redux docs, as they provide many best practices about global state management. It makes switching easier, if you need a full blown store later on. I'll assume here that you want use the useReducer
not just for one local ponent, but a more global state tree (thanks @DrewReese for the ment on this). If it's only about one ponent or so, your approach is perfectly fine!
Redux docs concerning basic state shape and wether an array is possible at the top level (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 mon 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.
So basically, its OK, but other libraries could be possibly opiniated and expect an object, as it is by far the most likely choice.
If you implement this shape, be sure that your requirement is to always need an undo action for your whole state. Because it es with a cost (besides mentioned 3rd party lib patibility):
- adds one additional level of nesting directly at the top level
- scalability and granularity (see next point)
What, if your app gets really huge and you have hundreds of reducers. Each time, your action is dispatched, there will be a new state object put in the history array, which could get messy. What, if you don't want a global undo, but a very fine granular one (in one particular reducer, say for one particular form element in the UI). You would have to distinguish between a global undo and a specific undo then. What instead about just one "UNDO" action which can be handled in each interested reducer in its own manner?
If that still fits your requirements, give it a try !
Cheers
It is possible, but as ford04 pointed out it may not be a great idea for a variety of reasons.
The demo below shows it works to use a plain array as the state
in 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./ajax/libs/react/16.8.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare./ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>
<div id="app"></div>
本文标签: javascriptCan useReducer work with an array for stateStack Overflow
版权声明:本文标题:javascript - Can useReducer work with an array for state? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1742220961a2435440.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论