I stumbled upon a strange behaviour due to my lack of knowledge and experience. I have a Component called inside another, looking like this:
<CustomSelectionButtons
values={roleTypes}
label="Roles:"
onSelect={setUserRoles}
selected={roles}
/>
roles is a state variable, which is set with the onSelect method (setUserRoles). Here it is:
const setUserRoles = (button: AccountsAndRolesUnion) => {
const updatedRoles: AccountsAndRolesUnion[] = roles; //this is the state variable.
/* doing something with the local **updatedRoles** array */
setRoles(updatedRoles);
};
If I use the code like this, the component does not rerender after setRoles hook call. However, If I assign the local variable with roles.slice(), everything works as expected, the component is rerendered. So, this works:
const setUserRoles = (button: AccountsAndRolesUnion) => {
const updatedRoles: AccountsAndRolesUnion[] = roles.slice(); //slicing the state variable.
/* doing something with the local **updatedRoles** array */
setRoles(updatedRoles);
};
Can someone explain why this happens?
Slice creates a shallow copy of the original array, meaning that it returns a different object than roles
itself, even though its content may be the same.
When you do setRoles(roles)
, you are actually sending the exact same object in memory, and when React compares the props before deciding whether to re-render, it doesn't detect any difference. However, when you do setRoles(roles.slice())
, you pass a different variable in memory, so React figures there is a change in props and re-renders.