Study notes
Track values, errors and submission through one coherent form model.
Read the explanation, run the worked example, then complete the matching Examples and Assignments tabs. Your original materials remain available alongside these notes.
Understand the idea
First understand a controlled form: input values come from state and onChange updates them. A form library then handles repetitive work such as registration, touched fields, validation and submission state. React Hook Form commonly registers inputs; Formik exposes values, errors, touched and handlers through components or useFormik.
Your student form exercises require labels, validation feedback and a submitted result. A valid form should submit once and preserve input when validation fails. Yup describes validation rules in a schema; client validation helps users but does not replace server validation. An asynchronous uniqueness check should handle network failure and outdated responses explicitly.
Run the example
Use a separate React practice project with a Node.js version supported by Vite. Create it once with these commands, then use its development URL. Do not paste this into the Edupoly website’s own source files.
npm create vite@latest react-practice -- --template react
cd react-practice
npm install
npm run dev
npm install formik yup react-hook-form
Replace src/App.jsx with the following complete example. Keep Vite’s generated src/main.jsx entry point.
src/App.jsx
import { useState } from 'react';
import { useFormik } from 'formik';
import * as Yup from 'yup';
export default function App() {
const [student, setStudent] = useState(null);
const form = useFormik({
initialValues: {name: '', email: ''},
validationSchema: Yup.object({name: Yup.string().trim().required('Name is required'), email: Yup.string().email('Enter a valid email').required('Email is required')}),
onSubmit(values, helpers) { setStudent({...values, name: values.name.trim()}); helpers.setSubmitting(false); }
});
return <main><form onSubmit={form.handleSubmit} noValidate>
<label>Name <input {...form.getFieldProps('name')} aria-describedby="name-error" /></label>
<p id="name-error">{form.touched.name && form.errors.name}</p>
<label>Email <input type="email" {...form.getFieldProps('email')} aria-describedby="email-error" /></label>
<p id="email-error">{form.touched.email && form.errors.email}</p>
<button disabled={form.isSubmitting}>Register</button>
</form>{student && <p>Registered {student.name}: {student.email}</p>}</main>;
}
Expected result
An empty submission shows required-field messages; a valid name and email produce a registration summary.
Alternative worked example — replace src/App.jsx
import { useState } from 'react';
import { useForm } from 'react-hook-form';
export default function App() {
const [student, setStudent] = useState(null);
const {register, handleSubmit, formState: {errors}} = useForm({defaultValues: {name: ''}});
return <main><form onSubmit={handleSubmit(setStudent)}>
<label>Name <input {...register('name', {required: 'Name is required', validate: value => value.trim().length > 0 || 'Enter a name'})} aria-describedby="name-error" /></label>
<p id="name-error" role="alert">{errors.name?.message}</p><button>Register</button>
</form>{student && <p>Registered {student.name}</p>}</main>;
}
Apply this to your assignments
Install formik, yup and react-hook-form in your practice app. Implement the same student fields with controlled state, React Hook Form, Formik/Field and useFormik. Compare blur errors, invalid submit, valid submit and reset. Add an async validation check against your own endpoint only after these paths work.
Your existing examples
- Form Handling Controlled Components
- Form Handling with react-hook-form
- Form Handling with Formik, Field components from formik library
- Advanced Form Handling using useFormik hook
- Form Validation using YUP schema custom synchronous and asynchronous validation
Open the Examples tab to run or inspect these supplied projects. Their original links are preserved.
Open Assignments for your complete original worksheet and submission controls.
Common mistakes
Never mix a library-managed field with unrelated state controlling the same value. Display errors after touch or submission instead of hiding failures.
Check your understanding
- Predict the output before running the example, then compare it with the result panel.
- Explain which value each expression reads and which action changes it.
- Try the boundary cases listed in the practice task and record what you observe.
- Rebuild one matching assignment without copying, then compare behavior with the original example.
Reference
Official documentation for this topic · Vite setup requirements
