Short Explanation I just want to get the data from the textboxes and send them to the server. In jquery I would just list out all my textboxes and get the value and form the json and send it to the server
Please see example code https://codesandbox.io/s/xenodochial-euclid-3bl7tc
const EMPTY_VALUE = "";
const App = () => {
const [valueFirstName, setValueFirstName] = React.useState(EMPTY_VALUE);
const [valueMiddleName, setValueMiddleName] = React.useState(EMPTY_VALUE);
const [valueLastName, setValueLastName] = React.useState(EMPTY_VALUE);
return (
<div>
First Name:
<Work365TextBox value={valueFirstName} setValue={setValueFirstName} />
<div>{valueFirstName}</div>
Middle Name:
<Work365TextBox value={valueMiddleName} setValue={setValueMiddleName} />
<div>{valueMiddleName}</div>
Last Name:
<Work365TextBox value={valueLastName} setValue={setValueLastName} />
<div>{valueLastName}</div>
</div>
);
};
Problem
The current code has a label for first name, middle name, and last name and components to contain the textboxes and then the state of the component is stored in the parent.Then the parent takes the state and displays it below the textbox. So the solution works great. But the code is messy
Question If I have a form that asks for 20 values what is a cleaner way to handle this ? I have tried to do this with by defining a object as json and calling a method when the value in each textbox changes but then I need to have a method for each textbox I have on the screen and it doesn't seem very clean. How would you solve this problem in a clean way ? Preferably I want to be able to have 50 textbox components but just call one method to update state.
CodePudding user response:
the object solution you mentioned is a great way.
one thing to add is that you can pass a name
prop to your input and then in the onChange method you can access it via event.target.name
that way you can dynamically update your object
something like this
const onChangeHandler = (event) => {
const name = event.target.name;
const value = event.target.value;
setState((prev) => ({ ...prev, [name]: value }));
};
another solution is to define it with useReducer but that will need a extra code.
CodePudding user response:
I would just use an array like that:
// one item for each textbox
const textboxes = [
{
// human-readable label
label: "First name",
// unique key for data access
key: "firstName"
},
{
label: "Middle name",
key: "middleName"
},
{
label: "Last name",
key: "lastName"
}
];
A state like this:
const [values, setValues] = React.useState(
// converts array to record-like object
Object.fromEntries(textboxes.map((box) => [box.key, ""]))
);
const handleChange = (key, value) => {
setValues((values) => ({ ...values, [key]: value }));
};
And render it like this:
<div>
{textboxes.map((box) => (
<>
{box.label}:
<Work365TextBox
value={values[box.key]}
setValue={(value) => handleChange(box.key, value)}
/>
<div>{values[box.key]}</div>
</>
))}
</div>