39
loading...
This website collects cookies to deliver better user experience
useSimpleReducer
offers an approach that is more intuitive and less verbose making it easier to create asynchronous actions.npm i @bitovi/use-simple-reducer
<div>
<button onClick={() => add(2)}>Add</button>
<div>
<p>Steps: {count}</p>
<div>{isActive ? <Loader /> : "Processing completed"}</div>
{error && <p>Error: {error}</p>}
</div>
</div>
add
async updates the serverisActive
displays a spinner while the action is running
count
will be updated when the state changes
error
will be of a non null value if the async action failed
type ActionType =
| { type: "LOADING" }
| { type: "ADD_SUCCESS", payload: number }
| { type: "ADD_FAILURE", payload: any };
type StateType = {
count: number,
isActive: boolean,
error: any,
};
const initialState = {
count: 0,
isActive: false,
error: null,
};
function Counter() {
const [{count, isActive, error}, dispatch] = useReducer(
(state: StateType, action: ActionType) => {
switch (action.type) {
case "LOADING":
return {
...state,
isActive: true,
};
case "ADD_SUCCESS":
return {
...state,
count: state.count + action.payload,
isActive: false,
error: null,
};
case "ADD_FAILURE":
return {
...state,
isActive: false,
error: action.payload,
};
default:
return state;
}
},
initialState
);
const add = (amount: number) => {
dispatch({ type: "LOADING" });
// An api call to update the count state on the server
updateCounterOnServer(state.count + amount)
.then(() => {
dispatch({ type: "ADD_SUCCESS", payload: amount });
})
.catch((error) => {
dispatch({ type: "ADD_FAILURE", payload: error });
});
};
return (
<div>
<button onClick={() => add(2)}>Add</button>
<div>
<p>Steps: {count}</p>
<div>{isActive ? <Loader /> : "Processing completed"}</div>
{error && <p>Error: {error}</p>}
</div>
</div>
);
}
type CounterState = { count: number };
const initialState = {
count: 0,
};
function Counter() {
const [state, actions, queue, error] = useSimpleReducer(
// initial state
initialState,
// collection of reducer methods
{
async add(state: CounterState, amount: number) {
// An api call to update the count state on the server
await updateCounterOnServer(state.count + amount);
return { ...state, count: state.count + amount };
},
}
);
return (
<div>
<button onClick={() => actions.add(2)}>Add</button>
<div>
<p>Steps: {state.count}</p>
<div>{queue.isActive ? <Loader /> : "Processing completed"}</div>
{error && <p>{error.reason}</p>}
</div>
</div>
);
}
switch
statement. Instead of having to extract a payload
from our action object, we can use simple function parameters.
dispatch
function, we get back a set of callbacks actions
, one for each of our "actions".
actions
value to call the reducer methods provided.queue.isActive
flag indicates whether the queue is currently processing any actions or not.queue.runningAction
and queue.pendingActions
are also exposed that can be used for debugging the current state of the queue.useSimpleReducer
hook returns an error
if any of the reducer methods fail.return (
<div>
<button onClick={()=> actions.add(2)}>Add</button>
<div>
<p>Steps: {state.count}</p>
<div>{queue.isActive ? : "Processing completed"}</div>
</div>
{error && <AlertDialog content={error.reason} onConfirm={() => error.runFailedAction()} />}
</div>
);
useReducer
. But I believe that useSimpleReducer
does it better in a way that is more intuitive to understand while offering extra capabilities.