0Pricing
React Native Academy · 课时

使用 Controller 设置 react-hook-form

安装 react-hook-form,使用 useForm 创建表单实例,并将每个 TextInput 包裹在 Controller 中进行注册,以接收 onChange/onBlur。

使用 Controller 设置 react-hook-form 是 CoddyKit 上的免费 React Native Academy 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 React Native Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 React Native Academy 课程共包含 4 节课。

本课时的部分内容尚未翻译,以英文显示。

Why react-hook-form?

react-hook-form is a performant, flexible library for building forms in React and React Native. Unlike manually wiring every input to useState, react-hook-form uses uncontrolled inputs to minimize re-renders. It integrates validation, error handling, and form submission into a single coherent API, and it works seamlessly with any UI component library through the Controller wrapper.

Installing react-hook-form

Install react-hook-form from npm. It has no dependencies and works with any React version 16.8+. No special configuration is needed — import its hooks and components directly into your React Native components after installation.

npm install react-hook-form

Creating a Form Instance with useForm

Call useForm() at the top of your component to create a form instance. It returns several utilities: control (for wiring inputs via Controller), handleSubmit (for form submission), formState.errors (for displaying validation errors), and reset (to clear all fields). Pass default values to useForm to pre-populate the form.

import { useForm } from 'react-hook-form';

interface LoginForm {
  email: string;
  password: string;
}

export default function LoginScreen() {
  const {
    control,
    handleSubmit,
    formState: { errors },
    reset,
  } = useForm<LoginForm>({
    defaultValues: { email: '', password: '' },
  });
}

Wrapping TextInput with Controller

In React Native, inputs are controlled components that need to be wrapped in Controller so react-hook-form can manage their values. Pass the control object, the field name, and a render prop. The render prop receives field which contains value, onChange, and onBlur to wire to the TextInput.

import { Controller } from 'react-hook-form';

<Controller
  control={control}
  name='email'
  render={({ field: { onChange, onBlur, value } }) => (
    <TextInput
      value={value}
      onChangeText={onChange}
      onBlur={onBlur}
      placeholder='Email'
      keyboardType='email-address'
      autoCapitalize='none'
    />
  )}
/>

Adding Validation Rules

Pass a rules prop to Controller to define validation constraints. The required rule marks a field as mandatory, minLength enforces a minimum character count, maxLength caps input length, and pattern validates against a regex. Each rule takes an object with a value and a message string shown when the rule fails.

<Controller
  control={control}
  name='email'
  rules={{
    required: { value: true, message: 'Email is required' },
    pattern: {
      value: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
      message: 'Enter a valid email address',
    },
  }}
  render={({ field: { onChange, onBlur, value } }) => (
    <TextInput value={value} onChangeText={onChange} onBlur={onBlur} />
  )}
/>

Displaying Field Errors

After Controller validates a field, any error is available in formState.errors[fieldName]. Access its message property and render it below the input in a red Text component. Errors only appear after the field has been touched (onBlur) or after the first submit attempt, preventing premature error messages.

<Controller
  control={control}
  name='email'
  rules={{ required: 'Email is required' }}
  render={({ field: { onChange, onBlur, value } }) => (
    <View>
      <TextInput
        value={value}
        onChangeText={onChange}
        onBlur={onBlur}
        style={[styles.input, errors.email && styles.inputError]}
      />
      {errors.email && (
        <Text style={styles.errorText}>{errors.email.message}</Text>
      )}
    </View>
  )}
/>

Handling Form Submission with handleSubmit

Wrap your submit handler with handleSubmit. react-hook-form will run all validation rules first; if any field is invalid, it populates formState.errors and does not call your handler. If all fields are valid, your handler receives a typed object containing all field values — ready to send to an API.

async function onSubmit(data: LoginForm) {
  console.log('Submitting:', data.email, data.password);
  try {
    await authApi.login(data.email, data.password);
    navigation.replace('Home');
  } catch (err) {
    Alert.alert('Login Failed', 'Invalid email or password.');
  }
}

<Button title='Log In' onPress={handleSubmit(onSubmit)} />

Password Field Configuration

For password fields, set secureTextEntry to hide the typed characters and configure an appropriate keyboard type. Wire the field to Controller exactly like the email field. Many apps also add a 'show/hide' icon button that toggles secureTextEntry via local state — this improves accessibility for users with typos.

<Controller
  control={control}
  name='password'
  rules={{
    required: 'Password is required',
    minLength: { value: 8, message: 'Password must be at least 8 characters' },
  }}
  render={({ field: { onChange, onBlur, value } }) => (
    <TextInput
      value={value}
      onChangeText={onChange}
      onBlur={onBlur}
      secureTextEntry
      placeholder='Password'
    />
  )}
/>

Using watch to Observe Field Values

The watch function returned by useForm lets you subscribe to a field's current value and react to changes in real time. A common use case is a 'confirm password' field that validates its value matches the password field. Pass a field name to watch and use the returned value in the confirm field's validate rule.

const { control, handleSubmit, watch, formState: { errors } } = useForm<RegisterForm>();
const password = watch('password');

<Controller
  control={control}
  name='confirmPassword'
  rules={{
    validate: (value) =>
      value === password || 'Passwords do not match',
  }}
  render={({ field }) => <TextInput {...field} secureTextEntry />}
/>

Resetting the Form

Call reset() to clear all field values and errors, returning the form to its default values. You can also pass a new set of values to reset({ email: 'prefilled@example.com' }) to re-initialize the form with different defaults, which is useful for edit-profile forms that pre-populate with existing user data.

// Clear after successful submit:
async function onSubmit(data: LoginForm) {
  await api.login(data);
  reset(); // clears all inputs
}

// Pre-fill with existing profile data:
useEffect(() => {
  if (userProfile) {
    reset({
      name: userProfile.name,
      email: userProfile.email,
    });
  }
}, [userProfile]);

Form Validation Modes

react-hook-form offers several mode settings that control when validation runs: 'onSubmit' (default, validates only on submit), 'onBlur' (validates when a field loses focus), 'onChange' (validates on every keystroke), and 'all' (combines onBlur and onChange). For mobile forms, 'onBlur' offers the best balance between immediate feedback and avoiding distracting errors while typing.

const { control, handleSubmit } = useForm<LoginForm>({
  mode: 'onBlur',       // validate when user leaves a field
  defaultValues: { email: '', password: '' },
});

Quick Check

Test your understanding of React Native Mobile Development concepts from this lesson.

Lesson Recap

In this lesson you learned: useForm creates the form instance with control, handleSubmit, and formState.errors, Controller wires native TextInput components to the form with onChange, onBlur, and value props, and rules define built-in validation constraints that populate errors automatically. Next up we explore validation rules and error message handling in depth.

常见问题解答

「使用 Controller 设置 react-hook-form」课时是免费的吗?

是的 — 「使用 Controller 设置 react-hook-form」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 React Native Academy 课程的其余内容,请升级到 CoddyKit PRO。 React Native Academy 课程共包含 4 节课。

「使用 Controller 设置 react-hook-form」这节课中我会学到什么?

安装 react-hook-form,使用 useForm 创建表单实例,并将每个 TextInput 包裹在 Controller 中进行注册,以接收 onChange/onBlur。 你通过在浏览器中直接运行的动手代码来练习 React Native Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 React Native Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 React Native Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。

「使用 Controller 设置 react-hook-form」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 React Native Academy 课中编写并运行代码吗?

能。每节 React Native Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 使用 Controller 设置 react-hook-form
  2. 验证规则与错误消息
  3. 使用表单状态构建多步骤表单
  4. 提交与重置表单
← 返回 React Native Academy