
Validaciones manuales, manejo de errores, estados touched y feedback visual.
Validación Manual
typescript1interface FormData { 2 name: string; 3 email: string; 4 password: string; 5 confirmPassword: string; 6} 7 8interface FormErrors { 9 name?: string; 10 email?: string; 11 password?: string; 12 confirmPassword?: string; 13} 14 15function RegisterForm() { 16 const [formData, setFormData] = useState<FormData>({ 17 name: "", 18 email: "", 19 password: "", 20 confirmPassword: "", 21 }); 22 23 const [errors, setErrors] = useState<FormErrors>({}); 24 const [touched, setTouched] = useState<Record<string, boolean>>({}); 25 26 const validate = (): FormErrors => { 27 const newErrors: FormErrors = {}; 28 29 // Validar nombre 30 if (!formData.name.trim()) { 31 newErrors.name = "El nombre es requerido"; 32 } else if (formData.name.length < 3) { 33 newErrors.name = "El nombre debe tener al menos 3 caracteres"; 34 } 35 36 // Validar email 37 const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; 38 if (!formData.email) { 39 newErrors.email = "El email es requerido"; 40 } else if (!emailRegex.test(formData.email)) { 41 newErrors.email = "Email inválido"; 42 } 43 44 // Validar contraseña 45 if (!formData.password) { 46 newErrors.password = "La contraseña es requerida"; 47 } else if (formData.password.length < 6) { 48 newErrors.password = "Mínimo 6 caracteres"; 49 } else if (!/(?=.*[0-9])/.test(formData.password)) { 50 newErrors.password = "Debe contener al menos un número"; 51 } 52 53 // Validar confirmación 54 if (formData.password !== formData.confirmPassword) { 55 newErrors.confirmPassword = "Las contraseñas no coinciden"; 56 } 57 58 return newErrors; 59 }; 60 61 const handleChange = (field: keyof FormData) => (value: string) => { 62 setFormData({ ...formData, [field]: value }); 63 64 // Limpiar error al escribir 65 if (errors[field]) { 66 setErrors({ ...errors, [field]: undefined }); 67 } 68 }; 69 70 const handleBlur = (field: keyof FormData) => () => { 71 setTouched({ ...touched, [field]: true }); 72 73 // Validar campo específico 74 const fieldErrors = validate(); 75 if (fieldErrors[field]) { 76 setErrors({ ...errors, [field]: fieldErrors[field] }); 77 } 78 }; 79 80 const handleSubmit = () => { 81 const validationErrors = validate(); 82 83 if (Object.keys(validationErrors).length > 0) { 84 setErrors(validationErrors); 85 setTouched({ 86 name: true, 87 email: true, 88 password: true, 89 confirmPassword: true, 90 }); 91 return; 92 } 93 94 // Enviar formulario 95 console.log("Formulario válido:", formData); 96 }; 97 98 return ( 99 <View style={styles.container}> 100 <View style={styles.inputContainer}> 101 <TextInput 102 style={[ 103 styles.input, 104 touched.name && errors.name && styles.inputError, 105 ]} 106 value={formData.name} 107 onChangeText={handleChange("name")} 108 onBlur={handleBlur("name")} 109 placeholder="Nombre completo" 110 /> 111 {touched.name && errors.name && ( 112 <Text style={styles.errorText}>{errors.name}</Text> 113 )} 114 </View> 115 116 <View style={styles.inputContainer}> 117 <TextInput 118 style={[ 119 styles.input, 120 touched.email && errors.email && styles.inputError, 121 ]} 122 value={formData.email} 123 onChangeText={handleChange("email")} 124 onBlur={handleBlur("email")} 125 placeholder="Email" 126 keyboardType="email-address" 127 autoCapitalize="none" 128 /> 129 {touched.email && errors.email && ( 130 <Text style={styles.errorText}>{errors.email}</Text> 131 )} 132 </View> 133 134 <View style={styles.inputContainer}> 135 <TextInput 136 style={[ 137 styles.input, 138 touched.password && errors.password && styles.inputError, 139 ]} 140 value={formData.password} 141 onChangeText={handleChange("password")} 142 onBlur={handleBlur("password")} 143 placeholder="Contraseña" 144 secureTextEntry 145 /> 146 {touched.password && errors.password && ( 147 <Text style={styles.errorText}>{errors.password}</Text> 148 )} 149 </View> 150 151 <View style={styles.inputContainer}> 152 <TextInput 153 style={[ 154 styles.input, 155 touched.confirmPassword && 156 errors.confirmPassword && 157 styles.inputError, 158 ]} 159 value={formData.confirmPassword} 160 onChangeText={handleChange("confirmPassword")} 161 onBlur={handleBlur("confirmPassword")} 162 placeholder="Confirmar contraseña" 163 secureTextEntry 164 /> 165 {touched.confirmPassword && errors.confirmPassword && ( 166 <Text style={styles.errorText}>{errors.confirmPassword}</Text> 167 )} 168 </View> 169 170 <TouchableOpacity style={styles.button} onPress={handleSubmit}> 171 <Text style={styles.buttonText}>Registrarse</Text> 172 </TouchableOpacity> 173 </View> 174 ); 175} 176 177const styles = StyleSheet.create({ 178 container: { 179 padding: 20, 180 }, 181 inputContainer: { 182 marginBottom: 15, 183 }, 184 input: { 185 height: 50, 186 backgroundColor: "white", 187 borderWidth: 1, 188 borderColor: "#ddd", 189 borderRadius: 8, 190 paddingHorizontal: 15, 191 fontSize: 16, 192 }, 193 inputError: { 194 borderColor: "#ff3b30", 195 }, 196 errorText: { 197 color: "#ff3b30", 198 fontSize: 12, 199 marginTop: 5, 200 marginLeft: 5, 201 }, 202 button: { 203 backgroundColor: "#007AFF", 204 height: 50, 205 borderRadius: 8, 206 justifyContent: "center", 207 alignItems: "center", 208 marginTop: 10, 209 }, 210 buttonText: { 211 color: "white", 212 fontSize: 18, 213 fontWeight: "600", 214 }, 215});
Ejemplos de Código
3 ejemplos
Regex de email simple
typescript
1```typescript
2const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
3```Estilo condicional de error
typescript
1```typescript
2style={[
3 styles.input,
4 touched.email && errors.email && styles.inputError,
5]}
6```Validación en submit
typescript
1```typescript
2const validationErrors = validate();
3if (Object.keys(validationErrors).length > 0) {
4 setErrors(validationErrors);
5 return;
6}
7```Recursos
5 recursos disponibles
¡Hora de Practicar!
PrácticaIntermedio15 min
Práctica
Practiquemos.
- Crear un formulario de registro con
name,email,password,confirmPassword. - Implementar
touchedpara mostrar errores solo al perder el foco. - Agregar estilos de error a inputs inválidos.
- Validar en
handleSubmity bloquear el envío si hay errores.
Desafío de Código
EjercicioIntermedio15 min
Ejercicios Prácticos
Realiza los ejercicios en el proyecto de la practica anterior
- Añade una regla para que la contraseña tenga al menos una mayúscula.
- Muestra un mensaje de error general si faltan campos obligatorios.
- Implementa validación de
emailcon un regex alternativo más estricto. - Resalta el primer campo con error haciendo focus automático.
Documentación Oficial
DocumentaciónPrincipiante0
Form Validation UX
Buenas prácticas para mostrar errores de validación.
Documentación Oficial
DocumentaciónPrincipiante0
React Native TextInput
Props relevantes para validación y feedback visual.
Documentación Oficial
DocumentaciónPrincipiante0
Accessibility in React Native
Recomendaciones para mensajes de error accesibles.