useReducer :
The useReducer
hook is a more complex and advanced way of managing state instead of the useState
hook.
reducer function
, which is a pure function which will take the "previous state" and the "action" as an argument and will then return the next state.const [count, dispatch] = useReducer(reducer, 0); // useReducer(function, initial state)
// now when is the reducer function called ? This is where "dispatch" comes into play, "dispatch" function can also be used to update the state.
reducer
function :
function reducer(state, action) {
console.log(state, action);
}
dispatch function :
const inc = function () {
dispatch(1); // this 1 is going to become the "action" in the reducer function
// setCount((count) => count + 1);
// setCount((count) => count + step);
};
- Output :
0 1
because the state
and action
are 0
and 1
.dispatch(x); // "x" becomes the "action" in the reducer function
// the "state" in the reducer function is the previous state.
reducer
is to take these two things "current state" and "action" and return the next state based on these two.Objects
in dispatch
function : type
& payload
: const [count, dispatch] = useReducer(reducer, 0); // useReducer(function, initial state)
const dec = function () {
dispatch({ type: "dec", payload: +1 });
// setCount((count) => count - 1);
// setCount((count) => count - step);
};
const inc = function () {
// dispatch(1); // this 1 is going to become the "action" in the reducer function
dispatch({ type: "inc", payload: +1 });
// setCount((count) => count + 1);
// setCount((count) => count + step);
};
const defineCount = function (e) {
// setCount(Number(e.target.value)); // when the input is empty, it will be 0
dispatch({type: "setCount", payload: Number(e.target.value)})
};
reducer
function :
function reducer(state, action) {
console.log(state, action);
if(action.type === 'inc') return state + action.payload;
if(action.type === 'dec') return state - action.payload;
if(action.type === 'setCount') return action.payload;
}
if an object is used as a state in a reducer function that an object of same structure has to be returned from that reducer function.
for example :
function reducer(state, action) {
console.log(state, action);
switch (action.type) {
case "dec":
return { ...state, count: state.count - 1 }; // here we are destructuring the state object and then overwriting the count property
case "inc":
return { ...state, count: state.count + 1 };
case "setCount":
return { ...state, count: action.payload };
case "setStep":
return { ...state, step: action.payload };
case "reset":
return {count: 0, step: 0};
default:
throw new Error("Unknown action type");
}
}
const initialState = { count: 0, step: 0 };
const [state, dispatch] = useReducer(reducer, initialState);
const { count, step } = state;
const defineStep = function (e) {
// setStep(Number(e.target.value));
dispatch({ type: "setStep", payload: Number(e.target.value) });
};
const reset = function () {
// setCount(0);
// setStep(1);
// instead of setting two states, we can now set both states at once using useReducer
dispatch({type: "reset"});
};
See react-quiz project for useReducer implementation