I was in a impression that both useState
and useReducer
works similarly except the fact that we should use useReducer when the state is complex/nested objects.
But today I found a strange behavior, I was looping over an array and setting the values to a state object. I did this same example using both useState
and useReducer
.
With useState
: It only pushes the last value from the array to the state object, as useState is async in nature, So when we setState inside a loop, it may not update properly based on previous state. So you get just the last one object inside the state.
With useReducer
: I was expecting the same behaviour with useReducer, but with useReducer, it seems to properly set the states when we dispatch
actions from inside a loop. So here you get all the objects inside the state.
useState
import React from 'react';
import ReactDOM from 'react-dom';
function App() {
const [students, setStudents] = React.useState({});
const createStudents = () => {
const ids = [1,2,3];
const names = ['john', 'michael', 'greg']
for(let i = 0; i < 3; i++){
const student = {[ids[i]]: names[i]};
setStudents({...students, ...student})
}
}
return (
<div className="App">
<button onClick={createStudents}>Create Students</button>
<br />
{JSON.stringify(students)}
</div>
);
}
useReducer
import React from 'react';
import ReactDOM from 'react-dom';
function App() {
const studentReducer = (state, action) => {
switch (action.type) {
case 'ADD':
return {...state, students: {...state.students, ...action.payload}};
default:
throw new Error();
}
}
const [students, dispatch] = React.useReducer(studentReducer, {students: {}});
const createStudents = () => {
const ids = [1,2,3];
const names = ['john', 'michael', 'greg']
for(let i = 0; i < 3; i++){
const student = {[ids[i]]: names[i]};
dispatch({type: 'ADD', payload: student})
}
}
return (
<div className="App">
<button onClick={createStudents}>Create Students</button>
<br />
{JSON.stringify(students)}
</div>
);
}