I have a client who wants a list of users listed in a table format, with the ability to change their “roles” using the Bootstrap Dropdowns. I’m able to get this working perfectly fine on codesandbox, but for whatever reason, when I try to run this on my own development environment, it updates ALL the buttons instead of just the one I clicked. It seems to be re-rendering all the buttons, even if I just change one.
Is there a better way to write this so it doesn’t re-render?
import { useState } from "react";
const users = [
{
name: "john",
role: "admin"
},
{
name: "tom",
role: "user"
},
{
name: "betty",
role: "user"
},
{
name: "pete",
role: "user"
},
{
name: "mark",
role: "user"
}
];
const roles = ["admin", "user"];
const RoleDropDown = (props) => {
const { role } = props;
const [newRole, setNewRole] = useState(role);
return (
<div className="dropdown">
<button
className="btn dropdown-toggle"
type="button"
data-bs-toggle="dropdown"
aria-expanded="false"
>
{newRole}
</button>
<ul className="dropdown-menu">
{roles.map((_role, j) => {
return (
<li key={j}>
<span
className={
newRole === _role ? "dropdown-item active" : "dropdown-item"
}
onClick={() => {
setNewRole(_role);
handleRoleChange(_role);
}}
>
{_role}
</span>
</li>
);
})}
</ul>
</div>
);
};
function handleRoleChange(role) {
console.log(`changed role to ${role}`);
}
export default function App() {
return (
<div className="App">
<table className="table">
<tr>
<th>Name</th>
<th>Role</th>
</tr>
{users.map((user, i) => {
return (
<tr key={i}>
<td>{user.name}</td>
<RoleDropDown role={user.role} />
</tr>
);
})}
</table>
</div>
);
}