I'm learning React and I recently encountered a bug that I couldn't trace.
Warning: Cannot update a component (`App`) while rendering a different component (`UserDisplayItem`). To locate the bad setState() call inside `UserDisplayItem
I then discovered that I was directly calling a passed down prop function within a div.
import React from "react";
import Card from "../Card/Card";
const UserDisplayItem = (props) => {
return (
<Card>
<div onClick={ props.onDeleteUser(props.id)}>
<div>{props.user.userName}</div>
<div>{props.user.age}</div>
</div>
</Card>
);
};
export default UserDisplayItem;
It then worked once I added a function to handle it:
import React from "react";
import Card from "../Card/Card";
const UserDisplayItem = (props) => {
// !!!!!!!! VERY IMPORTANT. ALWAYS MAKE YOUR OWN FUNCTION
const deleteHandler = () => {
props.onDeleteUser(props.id);
};
return (
<Card>
<div onClick={deleteHandler}>
<div>{props.user.userName}</div>
<div>{props.user.age}</div>
</div>
</Card>
);
};
export default UserDisplayItem;
So I'm happy it works but I want to understand why the other method didn't work. Any help will be appreciated, thanks.
CodePudding user response:
The issue isn't about function references, per se, but rather that in the first code example the function is being immediately invoked when the component is rendering instead of when the div
element is clicked.
onClick={props.onDeleteUser(props.id)}
You should instead use an anonymous callback:
onClick={() => props.onDeleteUser(props.id)}
or declare a local callback function like you did and pass the reference to it:
const deleteHandler = () => {
props.onDeleteUser(props.id);
};
...
onClick={deleteHandler}
An improvement could be to enclose the id
in the callback prior to it being passed in props.
Example:
<UserDisplayItem onDeleteUser={() => deleteUser(id)} user={....} />
...
const UserDisplayItem = ({ onDeleteUser, user }) => {
return (
<Card>
<div onClick={onDeleteUser}>
<div>{user.userName}</div>
<div>{user.age}</div>
</div>
</Card>
);
};