likes
comments
collection
share

手写实现 rc-field-form (六)

作者站长头像
站长
· 阅读数 14

「这是我参与2022首次更文挑战的第40天,活动详情查看:2022首次更文挑战」。

写在前面

  • 前面一篇文章,我们已经实现 Field 组件及时响应数据仓库数据更新时,组件的更新渲染
  • 今天我们来实现,数据的校验功能,以及 Form 接收的回掉

数据校验

  • 前面第一篇手写实现 rc-field-form 的文章已经展示了数据校验规则的传入方式,下面我们来回顾一下
const userRules = [{ required: true, message: "请输入账号" }];
const pwdRules = [{ required: true, message: "请输入密码" }];

// ...
<Field name="user" label="账号" rules={userRules}>
  <Input placeholder="请输入账号" />
</Field>

<Field name="pwd" label="密码" rules={pwdRules}>
  <Input placeholder="请输入密码" />
</Field>
// ...
  • 可以看到,数据的校验规则是,通过 props 直接传给 Field 组件的
  • 而我们上一篇文章,已经实现在数据仓库中注册 Field 组件实例,那么我们其实可以直接在数据仓库中轻松拿到数据的校验规则并进行校验
  • 下面时数据仓库中 validate 方法的实现
  validate = () => {
    const err = [];

    this.fieldEntities.forEach((field) => {
      const { name, rules } = field.props;

      const rule = rules && rules[0];
      const value = this.getFieldValue(name);

      if (rule && rule.required && !value) {
        err.push({
          [name]: rule.message,
          value,
        });
      }
    });

    return err;
  };
  • 这里很简单,直接判断的是数据非空的校验,实际上应该还有更多更丰富的校验逻辑,但这里我们的重点是了解 rc-field-form 的实现原理,所以我们回到 validate 的实现逻辑上
  • 遍历所有 Field 组件实例,取出他们对应的数据,进行校验,有错误时记录下来,最后直接返回一个错误数据的数组

注册数据校验的回掉函数

  • 上面实现了数据的校验,那么校验之后调用的回掉函数需要外部的输入,所以理论上也需要注册这些回掉
<Form form={form} onFinish={onFinish} onFinishFailed={onFinishFailed}>
    <Field name="user" label="账号" rules={userRules}>
      <Input placeholder="请输入账号" />
    </Field>

    <Field name="pwd" label="密码" rules={pwdRules}>
      <Input placeholder="请输入密码" />
    </Field>

    <button>Submit</button>
</Form>
  • 可以看到我们使用时,是通过 props 将 onFinishFailed、onFinish 等回掉函数传给 Form 组件的
  • 因此我们需要在 Form 组件中进行这个回掉函数的注册
export default function Form(
  { children, onFinishFailed, onFinish }
) {

  const [formStore] = useForm();


  // 注册 Form 上的回掉函数,数据校验后,提交数据时调用
  formStore.setCallbacks({
    onFinish,
    onFinishFailed,
  });

  return (
    <form
      onSubmit={(e) => {
        e.preventDefault();
        formStore.submit();
      }}
    >
      <FormContext.Provider value={formStore}>{children}</FormContext.Provider>
    </form>
  );
}
  • 这里有个关键点,为了能方便的使用自定义 hook useForm 拿到数据仓库的操作权限对象,所以 Form 组件写成了函数组件
  • 直接调用 setCallbacks 方法将接收的 props 中的回掉函数注册到数据仓库,下面是数据仓库中实现的注册回掉的方法
  // 注册回掉函数
  setCallbacks = (newCallbacks) => {
    this.callbacks = {
      ...this.callbacks,
      ...newCallbacks,
    };
  };
  
  
    // 暴露操作状态的方法
  getForm = () => ({
    getFieldsValue: this.getFieldsValue,
    setFieldsValue: this.setFieldsValue,
    setFieldValue: this.setFieldValue,
    getFieldValue: this.getFieldValue,
    registerField: this.registerField,
    setCallbacks: this.setCallbacks,
    submit: this.submit,
    // setRules: this.setRules,
  });
  • 这样就已经实现我们的回掉函数的注册了,然后顺便再实现一个 submit 函数
  // 提交所有数据
  submit = () => {
    const err = this.validate();
    const { onFinish, onFinishFailed } = this.callbacks;

    if (err.length) {
      // 数据校验有失败的
      onFinishFailed(err);
    } else {
      //数据校验全部通过
      onFinish({ ...this.store });
    }
  };
  • submit 函数直接调用上面实现的 validate 即可进行校验,然后根据校验结果,调用对应的回掉函数即可

小结

  • 至此,我们已经实现了数据的校验,数据的提交等功能
  • 但是我们如果想要在组件挂载后,给某个数据输组件设置一个默认值,应该怎么做呢?
  • 下篇文章,我们将完成整个 rc-field-form 功能的仿写

最后

  • 今天的分享就到这里了,欢迎大家在评论区里面进行讨论 👏。
  • 如果觉得文章写的不错的话,希望大家不要吝惜点赞,大家的鼓励是我分享的最大动力 🥰
转载自:https://juejin.cn/post/7068841936941121572
评论
请登录