Reputation: 43
I am a newbie. Im building a web application with React. I have a form with 18 fields.
I currently have a useState with initial value
const clientObj = { //18 fields };
const [client, setClient] = useState(clientObj);
For each input, I have something like this (example with field name):
<Form.Group>
<Form.Control
onChange={ e => { setClient( prev => ({...prev, name:e.target.value}))}}
placeholder="Your name"
type="text"
required/>
</Form.Group>
It works, however I doubt it is efficient. I want my web application to work efficiently. How should I handle a form with so many fields? Thanks :)
Upvotes: 2
Views: 6917
Reputation: 4519
You're good, leave your code like that. Or use a useReducer hook if you don't want to have multiple useState
(which is not a problem). Or follow the recommendation from Drew Reese answer to have a single object.
It works, however I doubt it is efficient. I want my web application to work efficiently.
What do you mean by that? If you're talking about performance (speed, memory use, etc.), you don't need to worry about it. React already does a good job to make your app efficient. Browser are more than capable to handle a form with many fields. It's a mistake to try to optmize things if you don't have a really good reason for it. Here is a nice article (although it talks about useMemo and useCallback) about this idea.
If you're talking about too many rerenders, you're probably fine as well! Don't get me wrong, it's better to have a cleaner code and avoid unnecessary rerenders. But you need to think about the balance of having a "complex code that makes your app more efficient in theory, but no real impact when using it" VS "a simple code, easy to understand/extend that is less efficient in theory, but when running the app you don't really feel that impact".
All that said, if you start to have infinite loops or states messing with each other, you definitely need to fix that. But then this is a bug and not an efficiency problem 😁
Here's another article that may help you understand more about rerenders.
Upvotes: 4
Reputation: 203418
Typically when working with form inputs and nested state you assign a name
attribute to each input and use a single onChange
handler. Since you are also using local component state and an onChange
handler then you might want to also ensure your inputs are fully controlled by also specifying the value
prop on the inputs.
const clientObj = { //18 fields };
const [client, setClient] = useState(clientObj);
const onChange = event => {
const { name, value } = event.target;
setClient(prevState => ({
...prevState, // shallow copy all previous state
[name]: value, // update specific key/value
}));
};
...
<Form.Control
name="name"
value={client.name}
onChange={onChange}
placeholder="Your name"
type="text"
required
/>
<Form.Control
name="lastName"
value={client.lastName}
onChange={onChange}
placeholder="Your last name"
type="text"
required
/>
<Form.Control
name="age"
value={client.age}
onChange={onChange}
placeholder="Your age"
type="text"
required
/>
...etc...
Upvotes: 8
Reputation: 31
I would suggest that as you tinker with your forms, you consider implementing a component for each type of form field you want to handle, so you can customize it and reuse it. If you change your mind as you go, you may find yourself having to refactor all of your code, whereas if you have your own components, you will be able to more easily propagate those changes.
If you go this route, it's important to think about what kind of parameters each kind of form field will have, so you can avoid refactors later.
For example:
function DropdownSelector({ label, value, onChange, options }) {
return (
<>
<label>label</label>
<Select value={value} onChange={onChange}>
{options.map((o) => {
return <option value={value}>{description}</option>
}}
</Select>
</>);
}
Then, as you figure out how you want your form to look, you can just tweak a small number of components until you get the desired look and behavior.
Upvotes: 1
Reputation: 115
Clean up:
const handleChange = (e) => setClient({ ...client, [e.target.name] : e.target.value})
return (
<input
name="lastName"
onChange{handleChange}
/>
);
Depending on your use case you may not even need to maintain state, just spread your client object into the form and your props to the appropriate inputs.
Alternatively useReducer is also an option
Upvotes: 1
Reputation: 319
Since you're using the useState hook. I would advice you to use the useReducer hook. useReducer works similarly to how redux works, and it looks cleaner in my opinion. Although performance wise there isn't a lot that is wrong with your example.
Upvotes: 1