'How to capture onChange event from a field with object type State
I am unable to capture the onChange event from a Obect which contains multiple object fields in itself.
Here is my useState hook.
const [train, setTrain] = useState({
trainNumber: "",
trainName: "",
fromStation: "",
toStation: "",
departureDateTime: "",
arrivalDateTime: "",
//unable to capture travelDetails property changes.
travelDetails: {
coachesClass: [
{
availableTickets: "",
travelClass: "",
fare: "",
},
],
},
});
Suppose I want to check the onChange event for travelDetails.coachesClass[0].availableTickets then how to do that?
<div className="row">
<label htmlFor="availableTickets">First AC</label>
<div className="col-4">
<input
type="number"
name="availableTickets"
className="form-control"
placeholder="Available Tickets"
required
value={train.travelDetails.coachesClass[0].availableTickets}
onChange={(e) => handleChange(e)}
/>
</div>
Here is the onChangeHandler
const handleChange = (e) => {
const { name, value } = e.target;
setTrain((prevState) => {
return {
...prevState,
[name]: value,
};
});
};
It is working fine for other fields but inside travelDetails it is not capturing changes.
Solution 1:[1]
The way you are updating state will need to be adjusted since you are trying to update a property in an array nested within an object. Try something like this:
const handleChange = (e) => {
setTrain((prevState) => {
const newCoachesClass = [...prevState.travelDetails.coachesClass];
newCoachesClass[0] = {
...prevState.travelDetails.coachesClass[0],
availableTickets: e.target.value
};
return {
...prevState,
travelDetails: {
...prevState.travelDetails,
coachesClass: newCoachesClass
}
};
});
};
Also since your input is of number type, you probably want to initialize availableTickets to a number instead of a string:
const [train, setTrain] = useState({
trainNumber: "",
trainName: "",
fromStation: "",
toStation: "",
departureDateTime: "",
arrivalDateTime: "",
travelDetails: {
coachesClass: [
{
availableTickets: 0,
...
Solution 2:[2]
Currently, your setState adds a new property on the state's object itself. Since it looks like you want that information to update your nested state, see updated snippet below:
const handleChange = (e) => {
const { name, value } = e.target;
setTrain((prevState) => {
return {
...prevState,
travelDetails: {
...prevState.travelDetails,
coachesClass: [
{
...prevState.travelDetails.coachesClass[0],
[name]: value
}
]
}
};
});
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Andrew Hulterstrom |
| Solution 2 |
