├── src ├── App.css ├── main.jsx ├── index.css ├── assets │ └── react.svg └── App.jsx ├── vite.config.js ├── .gitignore ├── index.html ├── README.md ├── package.json └── public └── vite.svg /src/App.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom/client' 3 | import App from './App' 4 | import './index.css' 5 | 6 | ReactDOM.createRoot(document.getElementById('root')).render( 7 | 8 | 9 | , 10 | ) 11 | -------------------------------------------------------------------------------- /vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | base: process.env.NODE_ENV !== 'development' ? '/react-hook-form-tutorial/' : '/', 8 | }) 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: #101010; 3 | color: white; 4 | display: flex; 5 | justify-content: center; 6 | align-items: center; 7 | min-height: 100vh; 8 | } 9 | 10 | label { 11 | display: block; 12 | } 13 | 14 | span { 15 | display: block; 16 | color: tomato; 17 | font-size: x-small; 18 | } 19 | 20 | input { 21 | margin-bottom: .3rem; 22 | } -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + React 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## React Hook Form Tutorial 2 | 3 | This is a tutorial on how to use React Hook Form. It is a library that helps you validate your forms in React. It is a very simple and easy to use library. It is also very lightweight and fast. It is a great alternative to Formik. 4 | 5 | ## Installation 6 | 7 | ```bash 8 | git clone https://github.com/fazt/react-hook-form-tutorial 9 | cd react-hook-form-tutorial 10 | npm install 11 | npm run dev 12 | ``` 13 | 14 | or you can try the live demo: https://fazt.github.io/react-hook-form-tutorial/ 15 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-hook-form-tutorial", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vite build", 9 | "preview": "vite preview", 10 | "deploy": "gh-pages -d dist" 11 | }, 12 | "dependencies": { 13 | "react": "^18.2.0", 14 | "react-dom": "^18.2.0", 15 | "react-hook-form": "^7.45.2" 16 | }, 17 | "devDependencies": { 18 | "@types/react": "^18.0.26", 19 | "@types/react-dom": "^18.0.9", 20 | "@vitejs/plugin-react": "^3.0.0", 21 | "gh-pages": "^5.0.0", 22 | "vite": "^4.0.0" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/react.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/App.jsx: -------------------------------------------------------------------------------- 1 | import { useRef } from "react"; 2 | import { useForm } from "react-hook-form"; 3 | 4 | function Formulario() { 5 | const { 6 | register, 7 | handleSubmit, 8 | formState: { errors }, 9 | watch, 10 | setValue, 11 | reset, 12 | } = useForm({ 13 | defaultValues: { 14 | nombre: "", 15 | correo: "", 16 | fechaNacimiento: "", 17 | password: "", 18 | confirmarPassword: "", 19 | pais: "co", 20 | archivo: "", 21 | aceptaTerminos: false, 22 | }, 23 | }); 24 | 25 | const password = useRef(null); 26 | password.current = watch("password", ""); 27 | 28 | const onSubmit = handleSubmit((data) => { 29 | console.log(data); 30 | // reset({ 31 | // nombre: '', 32 | // correo: '', 33 | // fechaNacimiento: '', 34 | // password: '', 35 | // confirmarPassword: '', 36 | // pais: 'ar', 37 | // archivo: '', 38 | // aceptaTerminos: false 39 | // }) 40 | reset(); 41 | }); 42 | 43 | return ( 44 |
45 |
46 | 47 | 59 | {errors.nombre?.type === "required" && Nombre requerido} 60 | {errors.nombre?.type === "maxLength" && ( 61 | Nombre no debe ser mayor a 20 caracteres 62 | )} 63 | {errors.nombre?.type === "minLength" && ( 64 | Nombre debe ser mayor a 2 caracteres 65 | )} 66 |
67 | 68 |
69 | 70 | 84 | {errors.correo && {errors.correo.message}} 85 |
86 | 87 |
88 | 89 | { 98 | const fechaNacimiento = new Date(value); 99 | const fechaActual = new Date(); 100 | const edad = 101 | fechaActual.getFullYear() - fechaNacimiento.getFullYear(); 102 | return edad >= 18 || "Debes ser mayor de edad"; 103 | }, 104 | })} 105 | /> 106 | {errors.fechaNacimiento && ( 107 | {errors.fechaNacimiento.message} 108 | )} 109 |
110 | 111 |
112 | 113 | 127 | {errors.password && {errors.password.message}} 128 |
129 | 130 |
131 | 132 | 145 | value === password.current || "Las contraseñas no coinciden", 146 | })} 147 | /> 148 | {errors.confirmarPassword && ( 149 | {errors.confirmarPassword.message} 150 | )} 151 |
152 | 153 |
154 | 155 | 160 | 161 | {watch("pais") === "ar" && ( 162 | 172 | )} 173 |
174 | 175 |
176 | 177 | { 180 | setValue("archivo", e.target.files[0].name); 181 | }} 182 | /> 183 | {errors.archivo && {errors.archivo.message}} 184 |
185 | 186 |
187 | 197 | 198 | {errors.aceptaTerminos && {errors.aceptaTerminos.message}} 199 |
200 | 201 | 202 | 203 |
{JSON.stringify(watch(), null, 2)}
204 |

Hello {watch("nombre")}

205 |
206 | ); 207 | } 208 | 209 | export default Formulario; 210 | --------------------------------------------------------------------------------