Reputation: 1
At the moment, I'm implementing user edit/create form. I'm keeping all information of user in one state so I just could send it to the backend.
My code looks like this:
const UserEditPage = () => {
const [user, setUser] = useState();
const [roles, setRoles] = useState([]);
}
const roleOnChange = (event, value) => {
if (user.roles.find(role => role === value)) {
setUser({ ...user, roles: user.roles.filter(role => role !== value) });
} else {
setUser({ ...user, roles: [...user.roles, value] });
}
}
useEffect(() => {
getRoles().then(res => {
setRoles(res.data);
}
}, []);
return (
<div>
{roles.map(role => {
<input type="checkbox" onChange={event => roleOnChange(event, role.id)}
checked={user.roles.find(userRole => userRole === role.id)} />
})}
</div>
)
The problem with that is when I click checkboxes they often doesn't get checked or unchecked.
I think the problem is previous setUser function doesn't fully get completed, and it can't see the new value. What do I need to do to fix this problem?
Upvotes: 0
Views: 352
Reputation: 3032
Yes, probably it can be... anyway if you have a set of values and you need to search some value in it - better use some indexed object instead of array. for example Set. And the code will be
const UserEditPage = () => {
const [user, setUser] = useState();
const [roles, setRoles] = useState([]);
}
const roleOnChange = (event, value) => {
const action = user.roles.has(value) ? 'delete' : 'add'
user.roles[action](value)
setUser({ ...user, roles: new Set(user.roles) });
}
return (
<div>
{roles.map(role => {
<input type="checkbox" onChange={event => roleOnChange(event, role.id)}
checked={user.roles.has(role.id)} />
})}
</div>
)
and even when you work with array, to learn if it has some value better use includes method as it works faster than find method and more meaningfull in this situation
user.roles.includes(value)
Upvotes: 1
Reputation: 736
One problem that i can see is that on every render, you calculate the checked
attribute of the checbox for N times where N is the amount of users.
This means that if you have 5 roles and 5 users you will calculate 5*5 times the checked attribute on each render.
You could use an object that holds the checked values based on role id and every time the checked changes, you change the value of the object only once. e.g
const [checkedHolder, updateCheckedHolder] = useState({role1: false, role2: false})
...
<input {...otherProps} checked={checkedHolder[roleId])} onChange={updateCheckedRoles[roleId]} />
and the use changer function:
I believe that this would drastically improve your performance since you won't have to iterate the roles on every render.
Upvotes: 0