Cours React Native · Module 5: Formulaires
React Hook Form - Des formulaires professionnels
Dans cette leçon4
React Hook Form est la bibliothèque de formulaires la plus populaire - efficace et facile à utiliser !
Installation
npx expo install react-hook-formFormulaire de base
import { useForm, Controller } from 'react-hook-form';
interface FormData {
name: string;
email: string;
password: string;
}
function RegisterForm() {
const {
control,
handleSubmit,
formState: { errors, isSubmitting },
} = useForm<FormData>({
defaultValues: {
name: '',
email: '',
password: '',
},
});
const onSubmit = async (data: FormData) => {
console.log('Données du formulaire :', data);
// Envoyer au serveur
};
return (
<View style={styles.container}>
<Controller
control={control}
name="name"
rules={{
required: 'Le nom est obligatoire',
minLength: { value: 2, message: 'Min. 2 caractères' },
}}
render={({ field: { onChange, onBlur, value } }) => (
<TextInput
style={[styles.input, errors.name && styles.inputError]}
placeholder="Nom"
onBlur={onBlur}
onChangeText={onChange}
value={value}
/>
)}
/>
{errors.name && (
<Text style={styles.error}>{errors.name.message}</Text>
)}
<Controller
control={control}
name="email"
rules={{
required: 'L\'email est obligatoire',
pattern: {
value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
message: 'Email invalide',
},
}}
render={({ field: { onChange, onBlur, value } }) => (
<TextInput
style={[styles.input, errors.email && styles.inputError]}
placeholder="Email"
keyboardType="email-address"
autoCapitalize="none"
onBlur={onBlur}
onChangeText={onChange}
value={value}
/>
)}
/>
{errors.email && (
<Text style={styles.error}>{errors.email.message}</Text>
)}
<Pressable
style={styles.button}
onPress={handleSubmit(onSubmit)}
disabled={isSubmitting}
>
<Text style={styles.buttonText}>
{isSubmitting ? 'Envoi...' : 'S\'inscrire'}
</Text>
</Pressable>
</View>
);
}Composant Input personnalisé
interface FormInputProps {
control: any;
name: string;
rules?: object;
placeholder?: string;
secureTextEntry?: boolean;
keyboardType?: KeyboardTypeOptions;
}
function FormInput({
control,
name,
rules,
placeholder,
secureTextEntry,
keyboardType,
}: FormInputProps) {
return (
<Controller
control={control}
name={name}
rules={rules}
render={({
field: { onChange, onBlur, value },
fieldState: { error },
}) => (
<View style={styles.inputContainer}>
<TextInput
style={[styles.input, error && styles.inputError]}
placeholder={placeholder}
onBlur={onBlur}
onChangeText={onChange}
value={value}
secureTextEntry={secureTextEntry}
keyboardType={keyboardType}
/>
{error && <Text style={styles.error}>{error.message}</Text>}
</View>
)}
/>
);
}
// Utilisation
function CleanForm() {
const { control, handleSubmit } = useForm();
return (
<View>
<FormInput
control={control}
name="name"
placeholder="Nom"
rules={{ required: 'Nom obligatoire' }}
/>
<FormInput
control={control}
name="email"
placeholder="Email"
keyboardType="email-address"
rules={{
required: 'Email obligatoire',
pattern: { value: /\S+@\S+\.\S+/, message: 'Email invalide' },
}}
/>
</View>
);
}Watch et setValue
function DynamicForm() {
const { control, watch, setValue } = useForm({
defaultValues: { country: '', city: '' },
});
const country = watch('country');
useEffect(() => {
// Réinitialiser la ville quand le pays change
setValue('city', '');
}, [country]);
return (
<View>
<FormInput control={control} name="country" placeholder="Pays" />
<FormInput control={control} name="city" placeholder="Ville" />
<Text>Pays sélectionné : {country}</Text>
</View>
);
}React Hook Form minimise les re-rendus et offre un excellent support de TypeScript !
Code de cette leçon : App.tsx
import React from 'react';
import { View, Text, TextInput, Pressable, StyleSheet } from 'react-native';
import { useForm, Controller } from 'react-hook-form';
interface FormData {
email: string;
}
export default function App() {
// TODO : récupère control, handleSubmit et formState: { errors } depuis useForm<FormData>()
// transmets defaultValues: { email: '' }
const onSubmit = (data: FormData) => {
console.log('Form data:', data);
};
return (
<View style={styles.container}>
{/* TODO : ajoute un <Controller> qui :
- prend control={control}
- a name="email"
- a rules={{ required: 'Email requis' }}
- dans render renvoie un <TextInput> avec onChangeText={onChange}, onBlur={onBlur}, value={value} */}
{/* TODO : sous le champ, affiche l'erreur : errors.email && <Text style={styles.error}>{errors.email.message}</Text> */}
<Pressable style={styles.button} onPress={handleSubmit(onSubmit)}>
<Text style={styles.buttonText}>Valider</Text>
</Pressable>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
justifyContent: 'center',
backgroundColor: '#1a5276',
},
input: {
backgroundColor: '#fff',
borderRadius: 8,
padding: 14,
fontSize: 16,
color: '#1a5276',
marginBottom: 8,
},
error: {
color: '#e74c3c',
marginBottom: 12,
},
button: {
backgroundColor: '#2980b9',
borderRadius: 8,
padding: 14,
alignItems: 'center',
},
buttonText: {
color: '#fff',
fontSize: 16,
fontWeight: '600',
},
});Entrées de la documentation utilisées dans cette leçon
Tu as repéré une erreur dans cette leçon ?
Teste tes connaissances
Réponds aux questions de cette leçon. Choisis une réponse pour voir tout de suite si elle est correcte.
1. Que retourne le hook useForm de react-hook-form ?
2. Comment ajoute-t-on la validation 'required' dans Controller ?
Tâches pratiques dans le jeu
- Tri vertical
Ordonne les éléments de Controller de l'extérieur vers l'intérieur :
- Éditeur de code
Complète le code avec useForm et Controller.