Kurs React Native · Moduł 5: Formularze
React Hook Form - Profesjonalne formularze
W tej lekcji4
React Hook Form to najpopularniejsza biblioteka do formularzy - wydajna i łatwa w użyciu!
Instalacja
npx expo install react-hook-formPodstawowy formularz
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('Form data:', data);
// Wysłanie na serwer
};
return (
<View style={styles.container}>
<Controller
control={control}
name="name"
rules={{
required: 'Imię jest wymagane',
minLength: { value: 2, message: 'Min. 2 znaki' },
}}
render={({ field: { onChange, onBlur, value } }) => (
<TextInput
style={[styles.input, errors.name && styles.inputError]}
placeholder="Imię"
onBlur={onBlur}
onChangeText={onChange}
value={value}
/>
)}
/>
{errors.name && (
<Text style={styles.error}>{errors.name.message}</Text>
)}
<Controller
control={control}
name="email"
rules={{
required: 'Email jest wymagany',
pattern: {
value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
message: 'Nieprawidłowy email',
},
}}
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 ? 'Wysyłanie...' : 'Zarejestruj'}
</Text>
</Pressable>
</View>
);
}Custom Input Component
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>
)}
/>
);
}
// Użycie
function CleanForm() {
const { control, handleSubmit } = useForm();
return (
<View>
<FormInput
control={control}
name="name"
placeholder="Imię"
rules={{ required: 'Imię wymagane' }}
/>
<FormInput
control={control}
name="email"
placeholder="Email"
keyboardType="email-address"
rules={{
required: 'Email wymagany',
pattern: { value: /\S+@\S+\.\S+/, message: 'Nieprawidłowy email' },
}}
/>
</View>
);
}Watch i setValue
function DynamicForm() {
const { control, watch, setValue } = useForm({
defaultValues: { country: '', city: '' },
});
const country = watch('country');
useEffect(() => {
// Reset miasta przy zmianie kraju
setValue('city', '');
}, [country]);
return (
<View>
<FormInput control={control} name="country" placeholder="Kraj" />
<FormInput control={control} name="city" placeholder="Miasto" />
<Text>Wybrany kraj: {country}</Text>
</View>
);
}React Hook Form minimalizuje re-rendery i oferuje świetne TypeScript support!
Kod do tej lekcji: 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: pobierz control, handleSubmit oraz formState: { errors } z useForm<FormData>()
// przekaż defaultValues: { email: '' }
const onSubmit = (data: FormData) => {
console.log('Dane formularza:', data);
};
return (
<View style={styles.container}>
{/* TODO: dodaj <Controller> który:
- przyjmuje control={control}
- ma name="email"
- ma rules={{ required: 'Email jest wymagany' }}
- w render zwraca <TextInput> z onChangeText={onChange}, onBlur={onBlur}, value={value} */}
{/* TODO: pod polem wyświetl błąd: errors.email && <Text style={styles.error}>{errors.email.message}</Text> */}
<Pressable style={styles.button} onPress={handleSubmit(onSubmit)}>
<Text style={styles.buttonText}>Wyślij</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',
},
});Hasła z dokumentacji w tej lekcji
Widzisz błąd w tej lekcji?
Sprawdź się
Odpowiedz na pytania z tej lekcji. Wybierz odpowiedź, a od razu zobaczysz, czy jest poprawna.
1. Co zwraca hook useForm z react-hook-form?
2. Jak dodać walidację 'required' w Controller?
Zadania praktyczne w grze
- Układanie w pionie
Uporządkuj elementy Controller od zewnętrznych:
- Edytor kodu
Uzupełnij kod z useForm i Controller.