npx expo install react-hook-form zod @hookform/resolvers> npm install --save react-hook-form zod @hookform/resolvers added 4 packages, changed 1 package, and audited 588 packages in 43s
useForm() returns control (the handle fields register with), handleSubmit, setError and formState. On the web you spread register('email') onto an <input>, and the library reads the DOM element's value. A TextInput has no DOM value, so each field registers through useController() (or <Controller>), which hands back value, onChange and onBlur to wire up. BookNest does that once, in a reusable Field:
export function Field<T extends FieldValues>({ control, name, label, ...input }: Props<T>) {
const { field, fieldState } = useController({ control, name });
const labelId = `${name}-label`;
return (
<View>
<Text style={ui.label} nativeID={labelId}>{label}</Text>
<TextInput
ref={field.ref} // lets handleSubmit focus the first error
value={field.value}
onChangeText={field.onChange}
onBlur={field.onBlur}
aria-labelledby={labelId}
style={[ui.input, fieldState.error && { borderColor: '#c62828', borderWidth: 2 }]}
{...input}
/>
<Text style={ui.error} aria-live="polite">{fieldState.error?.message ?? ''}</Text>
</View>
);
}Field is generic, so name must be one of the form's keys: name="emial" fails type checking with "Did you mean '"email"'?". In 7.88.0's source the defaults are mode: 'onSubmit', reValidateMode: 'onChange' and shouldFocusError: true: nothing complains until the first submit, then fields recheck per keystroke. 'onTouched' waits until a field loses focus, which suits phones.