I tried the following code but it did not work and I don't really understand the reason for it. Wanted to display the first name, last name and email. But with the following code it does not render.
// prevValue[name] = value;
// return prevValue;
I know the better option is using spread method. but just wondering why doesn't it render up?
Expected outcome:
import React, {
useState
} from "react";
function App() {
const [contact, setContact] = useState({
fName: "",
lName: "",
email: ""
});
function handleContact(event) {
const {
value,
name
} = event.target;
setContact((prevValue) => {
// prevValue[name] = value;
// return prevValue;
/*Logged result
{fName: "a", lName: "", email: ""}
{fName: "s", lName: "", email: ""}
{fName: "d", lName: "", email: ""}*/
if (name === "fName") {
return {
fName: value,
lName: prevValue.lName,
email: prevValue.email
};
}
});
/*Logged result
{fName: "", lName: "", email: ""}
{fName: "a", lName: "", email: ""}
{fName: "as", lName: "", email: ""}*/
console.log(contact);
}
return ( <
div className = "container" >
<
h1 >
Hello {
contact.fName
} {
contact.lName
} <
/h1> <
p > {
contact.email
} < /p> <
form >
<
input name = "fName"
placeholder = "First Name"
value = {
contact.fName
}
onChange = {
handleContact
}
/> <
input name = "lName"
placeholder = "Last Name"
value = {
contact.lName
}
onChange = {
handleContact
}
/> <
input name = "email"
placeholder = "Email"
value = {
contact.email
}
onChange = {
handleContact
}
/> <
button > Submit < /button> <
/form> <
/div>
);
}
export default App;
CodePudding user response:
When you call setContact
, You get the previous value of state as an argument
And you have the option to use the previous value of state to return the new desired value of state contact
For setting the firstName, You can do something like this
setContact(prev => {...contact, firstName: value})
So the onChange
handler for the <input />
can be
const handleFirstNameChange = () => {
setContact(prev => {...contact, firstName: value})
}
But you dont want to write three such handlers for firstName
, lastName
and emailAddress
just to update your contact state variable
So you can write a single wrapper function like
const handleContactChange = (attr, val){
setContact(prev => {...contact, attr: val})
}
CodePudding user response:
You have to notify the dom, that the object has been rendered by recreating it or iterating it. See the snippet below.
function App() {
const [contact, setContact] = React.useState({
fName: "",
lName: "",
email: ""
});
function handleContact(event) {
const { value, name } = event.target;
setContact((prevValue) => {
prevValue[name] = value;
return { ...prevValue };
});
}
return (
<div className="container">
<h1>
Hello {contact.fName} {contact.lName}{" "}
</h1>
<p> {contact.email} </p>
<form>
<input
name="fName"
placeholder="First Name"
value={contact.fName}
onChange={handleContact}
/>
<input
name="lName"
placeholder="Last Name"
value={contact.lName}
onChange={handleContact}
/>{" "}
<input
name="email"
placeholder="Email"
value={contact.email}
onChange={handleContact}
/>{" "}
<button> Submit </button>
</form>
</div>
);
}
// Render it
ReactDOM.render(
<App />,
document.getElementById("root")
);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.development.js"></script>