import React, { useState } from "react";
const Person = ({ id, name, age, deleteThisPerson }) => {
return (
<div className="person">
<p>{name}</p>
<p>{age}</p>
<button onClick={() => deleteThisPerson(id)}>Delete This Person</button>
</div>
);
};
const ArrayOfComponents = () => {
const deleteThisPersonHandler = (id) => {
console.log("[ArrayOfComponents] id : ", id);
console.log("[ArrayOfComponents] personArrOfComp : ", personArrOfComp);
};
const [personArrOfComp, setPersonArrOfComp] = useState([
<Person
id="pc1"
key="pc1"
name="pc1"
age={12}
deleteThisPerson={deleteThisPersonHandler}
/>,
]);
const addNewPersonHandler = () => {
let r = new Date().getTime();
setPersonArrOfComp((prevState) => {
return prevState.concat(
<Person
id={r}
key={r}
name={"PCC" + r}
age={Math.floor(Math.random() * 100)}
deleteThisPerson={deleteThisPersonHandler}
/>
);
});
};
return (
<div>
<button onClick={addNewPersonHandler}>Add New Person</button>
{personArrOfComp}
</div>
);
};
export default ArrayOfComponents;
Add some persons by clicking Add New Person button. After that when clicking on Delete This Person button, deleteThisPersonHandler function shows previous state, not the most current state.
Can anyone explain this behavior of ReactJs. Why the state is not updating in deleteThisPersonHandler function after adding new person.
It's because you're putting components on state which reference a lambda that closes over an old version of deleteThisPersonHandler
.
Components are not appropriate react state values. State should be the simplest possible data that your component needs to store to be able to render the UI. In this case that's probably a list of ids.
const [persons, setPersons] = useState(["pc1"]);
const addPerson = setPersons([...persons, Date.now()]);
return {persons.map(p => <Person
id={p}
key={p}
name={p}
age={12}
deleteThisPerson={deleteThisPersonHandler}
/>};
There, no components on state! You can swap out the scalar persons
with any complex object type you need.
It's because of the deleteThisPersonHandler
that you are passing as a prop. In setPersonArrOfComp
you are setting a new state, but it hasn't been updated yet. Your deleteThisPersonHandler
function that you are passing references the current state of personArrOfComp
, and not the state that you are attempting to currently update to. It will always be the previous state.
setPersonArrOfComp((prevState) => {
return prevState.concat(
<Person
id={r}
key={r}
name={"PCC" + r}
age={Math.floor(Math.random() * 100)}
deleteThisPerson={deleteThisPersonHandler}
/>
);
});
that's because you used a console.log() which shows the previous state, not the current state, your job is already done but it's the nature of the console.log(). so you can show your result as:
const deleteThisPersonHandler = (id) => {
alert("[ArrayOfComponents] id : "+ id);
alert("[ArrayOfComponents] personArrOfComp : "+ personArrOfComp);
};