Работа с формами
Формы в React Native — это комбинация TextInput, Pressable и валидации.
Простая форма
import { useState } from 'react';
import { View, Text, TextInput, Pressable, StyleSheet } from 'react-native';
export default function LoginForm() {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [error, setError] = useState('');
function handleSubmit() {
if (!email.includes('@')) {
setError('Некорректный email');
return;
}
if (password.length < 8) {
setError('Пароль минимум 8 символов');
return;
}
setError('');
console.log({ email, password });
}
return (
<View style={styles.container}>
<TextInput
value={email}
onChangeText={setEmail}
placeholder="Email"
keyboardType="email-address"
autoCapitalize="none"
style={styles.input}
/>
<TextInput
value={password}
onChangeText={setPassword}
placeholder="Пароль"
secureTextEntry
style={styles.input}
/>
{error ? <Text style={styles.error}>{error}</Text> : null}
<Pressable onPress={handleSubmit} style={styles.button}>
<Text style={styles.buttonText}>Войти</Text>
</Pressable>
</View>
);
}
Валидация
На лету или при отправке. На лету — через вычисляемые значения:
const emailError = email && !email.includes('@') ? 'Некорректный email' : '';
const passwordError = password && password.length < 8 ? 'Минимум 8 символов' : '';
Состояние формы
type FormState = {
email: string;
password: string;
errors: Partial<Record<keyof Omit<FormState, 'errors'>, string>>;
};
const [form, setForm] = useState<FormState>({
email: '',
password: '',
errors: {},
});
function update<K extends 'email' | 'password'>(key: K, value: string) {
setForm((f) => ({ ...f, [key]: value, errors: { ...f.errors, [key]: undefined } }));
}
React Hook Form
Работает в React Native:
npm install react-hook-form
import { useForm, Controller } from 'react-hook-form';
type FormValues = {
email: string;
password: string;
};
export default function Form() {
const { control, handleSubmit, formState: { errors } } = useForm<FormValues>({
defaultValues: { email: '', password: '' },
});
function onSubmit(data: FormValues) {
console.log(data);
}
return (
<View>
<Controller
control={control}
name="email"
rules={{ required: 'Email обязателен' }}
render={({ field }) => (
<TextInput
value={field.value}
onChangeText={field.onChange}
placeholder="Email"
/>
)}
/>
{errors.email && <Text>{errors.email.message}</Text>}
<Pressable onPress={handleSubmit(onSubmit)}>
<Text>Войти</Text>
</Pressable>
</View>
);
}
Controller нужен, потому что TextInput не поддерживает ref так же, как вебовый <input>.
Zod
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
const schema = z.object({
email: z.string().email('Некорректный email'),
password: z.string().min(8, 'Минимум 8 символов'),
});
const { control, handleSubmit } = useForm({
resolver: zodResolver(schema),
});
KeyboardAvoidingView
Клавиатура перекрывает форму — оберни в KeyboardAvoidingView:
import { KeyboardAvoidingView, Platform, ScrollView } from 'react-native';
<KeyboardAvoidingView
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
style={{ flex: 1 }}
>
<ScrollView keyboardShouldPersistTaps="handled">
{/* форма */}
</ScrollView>
</KeyboardAvoidingView>
Если ты уже знаешь React
В вебе — <form onSubmit={handleSubmit}>. В React Native нет form — отправка через нажатие на кнопку. Логика формы та же.
Итоги
- Нет
<form>— толькоPressable TextInputсonChangeText- React Hook Form работает
Controllerдля интеграции- Zod для схем валидации
KeyboardAvoidingViewпротив клавиатуры