Reputation: 49
I am beginner in react. I have following code:
import React, { useState, useEffect } from 'react';
import { Card, Form, Button } from 'react-bootstrap';
import Axios from 'axios'
export function StudentForm({ student, onSuccess, onError, setState }) {
const url = `http://localhost:9899/api/StudentData`;
const intialStudent = { Firstname: '', Middlename: '', Lastname: '', DOB: '', Gender: '' };
const [Student, setStudent] = useState(intialStudent);
useEffect(() => {
setStudent(student ? student : intialStudent);
}, [student]);
const SaveData = function (studentData) {
if (student._id) {
Axios.post(url, { ...studentData }, { headers: { 'accept': 'application/json' } })
.then(res => {
setState(null);
onSuccess(res);
})
.catch(error => {
alert('Error To Edit data');
});
}
else {
Axios.post(url, studentData, { headers: { 'accept': 'application/json' } })
.then(res => {
setState(null);
onSuccess(res);
})
.catch(err => onError(err));
}
}
return (
<Card>
<Card.Header><h5>{student ? "Edit" : "Add"} Student</h5></Card.Header>
<Card.Body>
<Form onSubmit={(e) => { e.preventDefault(); SaveData(Student); }}>
<Form.Group><Form.Control type="text" name="Firstname" placeholder="Firstname" value={Student.Firstname} onChange={e => { setStudent({ ...Student, Firstname: e.target.value }) }} /></Form.Group>
<Form.Group><Form.Control type="text" name="Middlename" placeholder="Middlename" value={Student.Middlename} onChange={e => setStudent({ ...Student, Middlename: e.target.value })} /></Form.Group>
<Form.Group><Form.Control type="text" name="Lastname" placeholder="Lastname" value={Student.Lastname} onChange={e => setStudent({ ...Student, Lastname: e.target.value })} /></Form.Group>
<Form.Group><Form.Control type="date" name="DOB" placeholder="DOB" value={Student.DOB} onChange={e => setStudent({ ...Student, DOB: e.target.value })} /></Form.Group>
<Form.Group><Form.Control type="text" name="Gender" placeholder="Class" value={Student.Gender} onChange={e => setStudent({ ...Student, Gender: e.target.value })} /></Form.Group>
<Button variant="primary" type="submit">Submit</Button>
</Form>
</Card.Body>
</Card>
);
}
In above code I am setting state on change event on each field. So it will render again and again when I change any of the field.If it is large form so it may take a lot of time to re-render so is there a better way to create to handle this kind of situation, or any best practices for using forms with react?
Upvotes: 3
Views: 2118
Reputation: 1116
You can use only one Function for all onChanges. Looks like this;
<Form.Group>
<Form.Control
type="text"
name="Firstname"
placeholder="Firstname"
value={Student.Firstname}
onChange={handleChange}
/>
</Form.Group>
And this is your handleChange function;
const handleChange = e => {
const {name, value} = e.target
setValues({...values, [name]: value})
}
This is your state;
const [values, setValues] = useState({
Firstname: "",
Middlename: "",
Lastname: "",
DOB: "",
Gender: ""
})
I think this way is more effective with less code.
Upvotes: 2
Reputation: 39250
You have to re render the form when an input changed but you don't need to re render every input when you make sure the onChange function doesn't change reference on every render and your input is a pure component (using React.memo for functional component and inherit from React.PureComponent for class components).
Here is an example of optimized inputs.
const {
useEffect,
useCallback,
useState,
memo,
useRef,
} = React;
function App() {
return <StudentForm />;
}
//put initial student here so it doesn't change reference and quits the linter
// in useEffect
const initialStudent = {
Firstname: '',
Middlename: '',
};
function StudentForm({ student }) {
const [Student, setStudent] = useState(initialStudent);
//useCallback so onChange is not re created and causes re rendering
// of components that didn't change
const onChange = useCallback(
(key, value) =>
setStudent(student => ({ ...student, [key]: value })),
[]
);
useEffect(() => {
setStudent(student ? student : initialStudent);
}, [student]);
const SaveData = function(studentData) {
console.log('saving data:', studentData);
};
return (
<form
onSubmit={e => {
e.preventDefault();
SaveData(Student);
}}
>
<InputContainer
type="text"
name="Firstname"
placeholder="Firstname"
value={Student.Firstname}
stateKey="Firstname" //provide state key
onChange={onChange}
/>
<InputContainer
type="text"
name="Middlename"
placeholder="Middlename"
value={Student.Middlename}
stateKey="Middlename"
onChange={onChange}
/>
<button type="submit">Submit</button>
</form>
);
}
//make this a pure component (does not re render if nothing changed)
const InputContainer = memo(function InputContainer({
type,
name,
placeholder,
value,
onChange,
stateKey,
}) {
const rendered = useRef(0);
rendered.current++;
return (
<div>
<div>{rendered.current} times rendered.</div>
<input
type={type}
name={name}
value={value}
placeholder={placeholder}
onChange={e =>
//pass state key and new value to onChange
onChange(stateKey, e.target.value)
}
/>
</div>
);
});
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Upvotes: 0
Reputation: 7051
Managing forms in react is a task complex enough to delegate it to a library. Alo, big forms are not a good candidate for functional components because the problems that you outlined. You can, of course, spend the time to tune it up, but I think the effort may not worth the benefit.
My personal recommendation is to try one of the many react form libraries out there. One that I personally like is Formik
If you want to manage the form yourself I recommend to encapsulate the form on stateful component and use the key property for easier reset when you need it.
Another alternative will be the usage of memoization, for example using react.memo. But that will not guarantee success unless your data has the proper shape. This means, simple values that can be compared between themselves, not arrays, not functions, not objects.
Upvotes: 2