MST
星途 面试题库

面试题:React 自定义 Hooks 实现表单状态管理

要求你创建一个自定义 Hook,用于管理表单的多个输入字段的状态,比如用户名、密码等。这个 Hook 要能够处理输入的变化、验证以及重置表单等功能。请给出完整的代码实现,并解释你设计这个 Hook 的思路。
32.7万 热度难度
前端开发React

知识考点

AI 面试

面试题答案

一键面试

代码实现

import { useState, useEffect } from 'react';

const useForm = (initialValues = {}, validationRules = {}) => {
    const [values, setValues] = useState(initialValues);
    const [errors, setErrors] = useState({});
    const [isSubmitting, setIsSubmitting] = useState(false);

    const handleChange = (e) => {
        const { name, value } = e.target;
        setValues({
           ...values,
            [name]: value
        });
        validateField(name, value);
    };

    const validateField = (field, value) => {
        const newErrors = {...errors };
        if (validationRules[field]) {
            const rule = validationRules[field];
            if (typeof rule ==='string') {
                if (!value.match(new RegExp(rule))) {
                    newErrors[field] = `Invalid ${field}`;
                } else {
                    delete newErrors[field];
                }
            } else if (typeof rule === 'function') {
                const errorMessage = rule(value);
                if (errorMessage) {
                    newErrors[field] = errorMessage;
                } else {
                    delete newErrors[field];
                }
            }
        }
        setErrors(newErrors);
    };

    const validateForm = () => {
        const newErrors = {};
        Object.keys(validationRules).forEach(field => {
            const value = values[field];
            const rule = validationRules[field];
            if (typeof rule ==='string') {
                if (!value.match(new RegExp(rule))) {
                    newErrors[field] = `Invalid ${field}`;
                }
            } else if (typeof rule === 'function') {
                const errorMessage = rule(value);
                if (errorMessage) {
                    newErrors[field] = errorMessage;
                }
            }
        });
        setErrors(newErrors);
        return Object.keys(newErrors).length === 0;
    };

    const handleSubmit = (e, onSubmit) => {
        e.preventDefault();
        setIsSubmitting(true);
        if (validateForm()) {
            onSubmit(values);
        }
        setIsSubmitting(false);
    };

    const resetForm = () => {
        setValues(initialValues);
        setErrors({});
    };

    return {
        values,
        errors,
        isSubmitting,
        handleChange,
        handleSubmit,
        resetForm
    };
};

export default useForm;

设计思路

  1. 状态管理
    • 使用 useState 钩子来管理表单的值 values、错误信息 errors 和提交状态 isSubmittinginitialValues 作为初始表单值传入,validationRules 用于定义每个字段的验证规则。
  2. 处理输入变化
    • handleChange 函数在输入框值变化时被调用。它通过解构 event.target 获取 namevalue,更新 values 状态,并调用 validateField 对当前字段进行验证。
  3. 字段验证
    • validateField 函数根据传入的 fieldvalue,结合 validationRules 进行验证。如果验证规则是字符串(当作正则表达式),则用正则匹配值;如果是函数,则调用该函数进行验证。验证通过则从 errors 中删除对应字段错误,否则添加错误信息。
  4. 表单验证
    • validateForm 函数对整个表单进行验证,遍历 validationRules 中的每个字段进行验证,收集所有错误信息并更新 errors 状态,最后返回是否所有字段都验证通过。
  5. 提交处理
    • handleSubmit 函数在表单提交时被调用,它先阻止默认提交行为,设置 isSubmittingtrue,调用 validateForm 验证表单。如果验证通过,调用传入的 onSubmit 函数并传入表单值,最后设置 isSubmittingfalse
  6. 重置表单
    • resetForm 函数将 valueserrors 状态重置为初始值,实现表单重置功能。
  7. 返回值
    • 最后返回一个对象,包含表单的 valueserrorsisSubmitting 状态,以及 handleChangehandleSubmitresetForm 函数,供组件使用以管理表单。