首页 > 其他分享 >如何优雅的处理 React 表单

如何优雅的处理 React 表单

时间:2023-05-14 21:44:21浏览次数:35  
标签:const import return 优雅 React joi Joi 表单

如何优雅的处理 React 表单

HTML 表单处理本身是一件比较简单的事情,但是当我们对交互的要求高了之后,他就会变得异常复杂——尤其是在 React 中使用时,我们不得不创建冗长的代码去维护各种状态。

那么有没有什么现成的开源方案可以供我们使用,最终优雅的创建 React 表单呢?

本文不会详细阐述每个库的用法、api,只是向大家介绍整合方案

如果我们直接写代码,大概率表单组件最后会是这样:

const [inputVal, setInputVal] = useState("");
const [errMessage, setErrMessage] = useState(null);
const isError = useMemo(() => Boolean(errMessage), [errMessage]);

function validate(val) {
  if (!val) {
    return "xxxx";
  }

  if (val.length > 10) {
    return "xxxx";
  }

  if (val.length < 2) {
    return "xxx";
  }

  return null;
}

function handleChange(e) {
  const value = e.target.value;
  setInputVal(value);

  const errMsg = validate(value);
  setErrMessage(errMsg);
}

return (
  <div>
    <input onChange={handleChange} />
    {isError && <p>{errMessage}</p>}
  </div>
);

我们仅仅只是校验了一个变量的长度和存在,就已经用了这么多的代码,还要处理三个状态!这太反人类了。

因此我们可以尝试使用如下四个库:react-hook-form, @hookform/resolvers, joi, joi-messages-zh_cn

优雅的表单处理

react-hook-form 可以非常方便的为我们创建一个表单,拥有更少的代码、更好的性能,并且可以配合所有的第三方库。

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

export default function App() {
  const {
    register,
    handleSubmit,
    watch,
    formState: { errors },
  } = useForm();
  const onSubmit = (data) => console.log(data);

  console.log(watch("example"));

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input defaultValue="test" {...register("example")} />

      <input {...register("exampleRequired", { required: true })} />
      {errors.exampleRequired && <span>This field is required</span>}

      <input type="submit" />
    </form>
  );
}

配合 Material-UI:

import Select from "react-select";
import { useForm, Controller } from "react-hook-form";
import Input from "@material-ui/core/Input";

const App = () => {
  const { control, handleSubmit } = useForm({
    defaultValues: {
      firstName: "",
      select: {},
    },
  });
  const onSubmit = (data) => console.log(data);

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <Controller
        name="firstName"
        control={control}
        render={({ field }) => <Input {...field} />}
      />
      <Controller
        name="select"
        control={control}
        render={({ field }) => (
          <Select
            {...field}
            options={[
              { value: "chocolate", label: "Chocolate" },
              { value: "strawberry", label: "Strawberry" },
              { value: "vanilla", label: "Vanilla" },
            ]}
          />
        )}
      />
      <input type="submit" />
    </form>
  );
};

优雅的校验

joi 是一个用来校验 JavaScript 类型的库。

我们可以定义一个 Schema:

const schema = Joi.object({
  username: Joi.string().max(12).min(2).required(),
  password: Joi.string().min(6).required(),
});

通过 @hookform/resolvers 库我们可以将 schema 传递给 react-hook-form 用来校验表单数据。

但现在有一个问题,那就是所有的报错都是英文,该如何切换为中文呢?

这就需要用到 Joi 的 defaults 方法了。

// my_joi.js
import Joi from "joi";
import cnMessages from "joi-messages-zh_cn";

export default Joi.defaults((schema) =>
  schema.options({
    messages: { ...cnMessages["zh-cn"] },
  })
);

messages 是我们的自定义消息,joi-message-zh_cn 这个库已经为我们写好了中文的报错消息。

最后,在定义 scheme 时,加上 .label('用户名'),就可以讲报错消息彻底改换为中文了。

最终效果

这里放一段使用 material ui 的例子:

// 这里使用 defaults 封装过的 Joi
const schema = Joi.object({
  username: Joi.string().max(12).min(2).required().label("用户名"),
  password: Joi.string().min(6).required().label("密码"),
});

function LoginForm({ onSubmit }) {
  const {
    control,
    handleSubmit,
    register,
    formState: { errors },
  } = useForm({
    defaultValues: {
      username: "",
      password: "",
    },
    resolver: joiResolver(schema),
  });

  function formError(field) {
    const err = errors[field];
    return {
      error: Boolean(err),
      helperText: err?.message,
    };
  }

  return (
    <form onSubmit={handleSubmit(onSubmit)} className={styles.wrapper}>
      <Controller
        name="username"
        control={control}
        render={({ field }) => (
          <TextField
            {...field}
            {...register("username")}
            className={styles.item}
            variant="standard"
            label="用户名"
            required
            {...formError("username")}
          />
        )}
      />
      <Controller
        name="password"
        control={control}
        render={({ field }) => (
          <TextField
            {...field}
            {...register("password")}
            className={styles.item}
            variant="standard"
            type="password"
            label="密码"
            required
            {...formError("password")}
          />
        )}
      />
      <Button type="submit">提交</Button>
    </form>
  );
}

标签:const,import,return,优雅,React,joi,Joi,表单
From: https://www.cnblogs.com/xhyccc/p/17400318.html

相关文章

  • AntDesign的Form表单内容有值但是仍然报请输入的错误
    案例解决方案a-form标签上有:model="formState"a-form-item中的name值和v-model:value对应值保持一致案例<a-form:label-col="labelCol":wrapper-col="wrapperCol"ref="formRef":model="formState">......
  • 基于jeesite如何实现多tab页切换时,对应Form表单进行刷新?
    思路:点击tab切换时,触发form表单的submit请求,从而实现刷新效果1、给tab加id:<liclass="active"><ahref="#tab-1"id="prepareTab"data-toggle="tab">待办事项</a></li>2、增加一个查询按钮,发送submit请求,可以隐藏<buttontype="submit&quo......
  • 表单域(html)
    <!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metahttp-equiv="X-UA-Compatible"content="IE=edge"><metaname="viewport"content="width=device-width,init......
  • 如何优雅得关闭协程呢
    1.简介本文将介绍首先为什么需要主动关闭goroutine,并介绍如何在Go语言中关闭goroutine的常见套路,包括传递终止信号和协程内部捕捉终止信号。之后,文章列举了需要主动关闭协程运行的常见场景,如启动一个协程执行一个不断重复的任务。希望通过本文的介绍,读者能够掌握如何在适当的时......
  • css条件选择器has,给layui必填表单的label增加红色星号
    使用lay-reqtext而不应lay-verify或者lay-verify="required",是为了防止 lay-verify="required|monolog"和lay-verify=“自定义验证规则”(有时候不是必填项,但是填写以后要检查格式)。.layui-form-label:has(+divinput[lay-reqtext]):has条件选择器,括号里是选择条件,+div兄弟元......
  • 在python3.7+中优雅的使用dataclass
    [本文出自天外归云的博客园]在Python3.7+中,dataclasses是一个非常优雅的工具,可以轻松地创建简单的类,并自动生成常见的类方法,比如 __init__、__repr__ 等。以下是一些使用dataclasses时需要注意的事项:导入dataclasses模块在使用dataclasses之前,需要先导入datacla......
  • react Ref 什么时候用,怎么用
    何时使用ref通常,当你的组件需要“跳出”React并与外部API通信时,你会用到ref——通常是不会影响组件外观的浏览器API。以下是这些罕见情况中的几个:存储timeoutID存储和操作DOM元素存储不需要被用来计算JSX的其他对象。如果你的组件需要存储一些值,但不影......
  • useCallback,useMemo, React.memo的区别
     同:useCallback,useMemo和React.memo是三个在React中用于优化性能的方法。它们的主要目标是避免不必要的重新渲染和计算。因为当一个组件的状态发生变化时,React会重新渲染整个组件树。用这三个hook和组件,可以提升性能。 异:下面从属性,接收参数,返回值,意义和案例等方面进行详细地......
  • layui表单验证抽离成单独模块手动调用
    模块名:validateForm可以多个表单一起验证,任何任何一个验证不通过就会返回。使用:varboolResult=validateForm.validate("formId1","formId2",....)模块定义如下:1/**2扩展一个表单手动验证模块3**/45layui.define(['layer','form'],function(expo......
  • react useReactStore.js
    import{useCallback,useEffect,useMemo,useRef,useState}from'react';import_getfrom'lodash.get';import_setfrom'lodash.set';exportconstKEY_SAVED_TICK_COUNT='KEY_SAVED_TICK_COUNT';exportclassGlo......