⚫ React Hooks 精进 13 - Hooks给Form带来的新变化


在表单中使用 React 组件:受控组件和非受控组件

非受控组件:表单元素的值不是由副组件决定的,是完全内部的状态

通过非受控组件的方式,可以避免某些程度上的组件重复渲染导致的性能问题,但是无法对外有交互。

使用 Hooks 简化表单处理

维护表单组件的状态逻辑,核心在于:字段名,value 值,onChange 事件

这就是很多组件库里的 useForm 这个功能,可以通过提供字段名去取值和设值,就不需要繁琐地为每个表单元素设置状态。

核心原理:把表单的状态管理单独提取出来, 成为一个可重用的 Hook。

处理表单验证

  • 如何定义错误状态
  • 如何设置错误状态

可以传递 validators 对象给 useForm 这个 Hook,然后在 hook 内在 setFieldValue 时对其进行验证,并在返回时返回错误信息给调用者。

关键就是在于把表单状态逻辑和 UI 展示逻辑给予 Hooks 进行分离。

import { useState, useMemo, useCallback } from "react";

const useForm = (initialValues = {}, validators) => {
  const [values, setValues] = useState(initialValues);
  const [errors, setErrors] = useState({});

  const setFieldValue = useCallback(
    (name, value) => {
      setValues((values) => ({
        ...values,
        [name]: value,
      }));

      if (validators[name]) {
        const errMsg = validators[name](value);
        setErrors((errors) => ({
          ...errors,
          [name]: errMsg || null,
        }));
      }
    },
    [validators]
  );

  return { values, errors, setFieldValue };
};

export default () => {
  const validators = useMemo(() => {
    return {
      name: (value) => {
        if (value.length < 2) return "Name length should be no less than 2.";
        return null;
      },
      email: (value) => {
        if (!value.includes("@")) return "Invalid email address";
        return null;
      },
    };
  }, []);
  const { values, errors, setFieldValue } = useForm({}, validators);
  const handleSubmit = useCallback(
    (evt) => {
      evt.preventDefault();
      console.log(values);
    },
    [values]
  );
  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label>Name: </label>
        <input
          value={values.name || null}
          onChange={(evt) => setFieldValue("name", evt.target.value)}
        />
        {errors.name && <span style={{ color: "red" }}>{errors.name}</span>}
      </div>

      <div>
        <label>Email:</label>
        <input
          value={values.email || null}
          onChange={(evt) => setFieldValue("email", evt.target.value)}
        />
        {errors.email && <span style={{ color: "red" }}>{errors.email}</span>}
      </div>
      <button type="submit">Submit</button>
    </form>
  );
};

思考题

  1. 如何在自定义的 useForm Hook 中提供 reset 的 API?

    就是返回一个置空的函数。

  2. 在自定义的 useForm 内如何实现支持异步验证?


文章作者: 阿汪同学
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 阿汪同学 !
评论
  目录