Following this question, I would like to replace the TextField (to input the age) component to use a Select component since I notice both have the inputProps property.
Original app:
function App() {
const [state, setState] = React.useState({
cats: [{ name: "cat1", age: "2" }, { name: "cat2", age: "5" }],
owner: "Owner's Name"
});
const handleFormChange = e => {
if (["name", "age"].includes(e.target.dataset.fieldType)) {
const newCats = [...state.cats];
newCats[e.target.dataset.id][e.target.dataset.fieldType] = e.target.value;
setState({ ...state, cats: newCats });
} else {
setState({ ...state, [e.target.name]: e.target.value });
}
};
return (
<form onChange={handleFormChange}>
<TextField label="Owner" value={state.owner} name="owner" />
<br />
<br />
<TextField
label="Name 1"
value={state.cats[0].name}
inputProps={{ "data-id": 0, "data-field-type": "name" }}
/>
<TextField <-----------------------replace with a Select
label="Age 1"
value={state.cats[0].age}
inputProps={{ "data-id": 0, "data-field-type": "age" }}
/>
</form>
);
}
The Select component I'm replace the second TextField:
<Select
onChange={handleSelectChange}
label={"Age 1"}
value={state.cats[0].age}
inputProps={{
"data-id": idx,
"data-field-type": "age",
name: "customName"
}}
>
<MenuItem value={10}>Ten</MenuItem>
<MenuItem value={20}>Twenty</MenuItem>
<MenuItem value={30}>Thirty</MenuItem>
</Select>
But in my handleSelectChange function:
const handleSelectChange = e => {
console.log("value", e.target.value); //OK
console.log("name", e.target.name); // OK
console.log("dataset", e.target.dataset); //undefined
};
The data attributes passed to the inputProps are undefined, why is that?
This is a codesandbox I made testing this behaviour: https://codesandbox.io/s/dynamic-form-change-handler-with-select-ft4dj
Best Answer
For Material-UI's
Select
, the event that triggers theonChange
is actually a click on aMenuItem
. Here is a slightly simplified (ignoring themultiple
case) version of that code:Notice that the event target is explicitly created here as an object with only
value
andname
properties. The original click event target would not generally be helpful since it wouldn't correspond to a consistent DOM element representing theSelect
, but would instead be some DOM element within the particularMenuItem
that was clicked.When answering your previous question, I avoided starting a discussion about whether the approach in the tutorial is a good one since I wanted to avoid getting into more opinion-based aspects; however, this scenario forces the discussion. In general, in React I think it is best to avoid putting extra stuff in the DOM so that event handlers can pull the information back out. Instead, just provide the event handler directly with the information.
For instance you could have:
In the code snippet above, the index and field type are passed to
handleSelectChange
to return a change handler that knows that information without it ever needing to be part of the DOM.Here's a modified version of your sandbox with this working: https://codesandbox.io/s/dynamic-form-change-handler-with-select-1sihp
This same approach could also be used for the text inputs.